基于组件的游戏设计中的共享字段

2024-04-29

我认为这是使用 XNA 在 C# 中完成基于组件的游戏引擎之前的最后一个逻辑飞跃。我定义了实体类和抽象组件。我的问题出现在我的 EntityFactory 中。

当我想创建一个新实体时,我将 EntityType 枚举传递给工厂中的静态方法,然后它通过 switch/case 语句查找要组合在一起的组件。问题是,我试图创建一种方法,使组件可以与同一实体中的其他组件共享字段,而无需它们访问所有内容。例如,如果两个组件都有表示位置的 Vector2 字段,则它们应该都指向同一个 Vector2。

我可以通过初始化实体工厂中的所有字段并要求将它们传递到组件的构造函数中(并使用原语的 ref )来做到这一点,但这将非常难以维护,因为任何时候我扩展或更改组件,我必须在工厂中使用该组件的每个地方重写代码。我真的很想避免这种解决方案,但如果我找不到更好的方法,我会忍受它。

我当前的解决方案是创建一个名为 Attribute 的包装类。它包含两个字段:

private AttributeType type;
private Object data;

属性类型是一个枚举,表示属性的用途。所以枚举中有Position、Rotation、Texture等条目。

EntityFactory 创建一个空的属性列表,并将其传递给每个组件构造函数。 setField 方法将由组件的构造函数调用,而不是初始化字段。这是 Attribute 类和 setField 方法。

 public class Attribute
{
    private AttributeType type;
    private Object data;

    public AttributeType Type
    {
        get { return this.type; }
    }
    public Object Data
    {
        get { return this.data; }
    }

    public Attribute(AttributeType type, Object data)
    {
        this.type = type;
        this.data = data;
    }

    public static void setField<T>(List<Attribute> attributeList, AttributeType type, out T field, T defaultValue)
    {
        bool attributeFound = false;
        field = defaultValue;

        foreach (Attribute attribute in attributeList)
        {
            if (attribute.Type == type)
            {
                field = (T)attribute.Data;
                attributeFound = true;
                break;
            }
        }

        if (!attributeFound)
        {
            attributeList.Add(new Attribute(type, field));
        }
    }
}

我的问题是当属性包含原始类型的数据时。我考虑在 Attribute 类中编写一个方法

public void getData<T>(out T field) { field = this.data; }

但是我似乎无法使用 ref 将数据传递给属性构造函数。我无法使属性通用,因为它不会进入列表。我只是想知道是否有一种方法可以处理值类型和引用类型数据,或者我在整个事情的某个地方犯了逻辑错误。


尖刻版本:恭喜您重新发明了变量。糟糕。或者,充其量是接口上的属性。

有用的版本:

我可以看到您的设计存在一些问题。

第一个问题很简单复杂的。最好避免复杂化,除非你有令人信服的和existent其原因(即:不是“也许在未来”的需要)。否则YAGNI https://en.wikipedia.org/wiki/YAGNI。在求助于创建系统来在数据中表达这些概念之前,您应该始终尝试直接在代码中表达概念(就像我所说的重新发明变量;还可以考虑this https://en.wikipedia.org/wiki/Greenspuns_Tenth_Rule).

但我们假设您确实有充分的理由进行基于组件的设计......

第二个问题是boxing。装箱发生在您存储值类型的任何地方(例如:int, float, Vector2, any struct)直接作为引用类型(例如:object, IEquatable)。装箱对象是不可变的 - 因此每次您的位置发生变化时,都会创建一个新的装箱对象。装箱变量(相对)慢。装箱对象存储在堆上 - 因此它们在垃圾收集期间被考虑,并且可能导致垃圾收集。所以你在问题中提出的设计将会执行horribly.

我认为您对基于组件的设计的想法类似于这篇文章中解释的 https://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/。这是一个有用的图表:


(source: cowboyprogramming.com http://cowboyprogramming.com/images/eyh/Fig-2.gif)

这让我想到了第三个问题:你不应该有多个组件占据一位置反正! (你好像要去way在设计中比您需要的更细化。)

基本上,基于组件的设计是关于重新发明class,而不是variable. In a normal设计时,你可能有一个像这样的“渲染”功能:

public void Draw()
{
    spriteBatch.Draw(texture, this.Position, Color.White);
}

但在基于组件的设计中,您将拥有Draw and Position in 不同的班级。顺便说一句,我会实现如下接口:

interface IRenderComponent { void Draw(); }
interface IPositionComponent { Vector2 Position { get; set; } }

那么如何Draw access Position?那么,你需要一种表达方式this(如果你要重新发明类,this也许是您需要包含的最重要的概念)。

你会怎么做?这是给您的一个粗略的设计思路:

我会让每个组件类继承自Component具有属性的类Self。我会让Self返回某种ComposedObject具有通过接口访问构成组合对象的任何其他组件的机制。所以也许你的渲染组件可能看起来像:

class SimpleRenderer : Component, IRenderComponent
{
    public void Draw()
    {
        sb.Draw(texture, Self.Get<IPositionComponent>().Position, Color.White);
    }
}

(这与以下操作类似GameServiceContainer(即:Game.Services财产)。这里的想法是不ComposedObject每个接口应该有多个实例。如果您的接口数量很少,ComposedObject甚至不需要使用列表 - 只需直接存储每个列表即可。不过,您可以拥有实现多个接口的组件。)

现在,如果这对您来说太冗长,也许您可​​以添加一些方便的属性ComposedObject(或使用扩展方法)对于常见的数据片段,例如Position, 像这样:

public Vector2 Position { get { return Get<IPositionComponent>().Position; } }

那么你的绘制函数可以是这样的:

spriteBatch.Draw(texture, Self.Position, Color.White);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于组件的游戏设计中的共享字段 的相关文章

随机推荐

  • 更改 WCF 中的命名空间和 schemaLocation 属性

    我用 C 开发了一个 WCF 服务 我们的客户已经有一个用 Java 编写的客户端软件 他们说当他们尝试添加我们的 wcf 服务引用时 他们收到错误 他们认为问题在于命名空间 我对 WCF 中的命名空间或任何其他标记详细信息了解不多 他们说
  • Android - Google+ 共享状态失败

    我查看了 Google 关于如何将 Android 应用程序的状态共享到 Google 的说明 https developers google com mobile android share https developers google
  • $(sel).bind("click", $(sel).click(, $(sel).live("click", $(sel).on("click") 之间有什么显着差异?

    我已经使用它们很长一段时间了 但大多数时候 我更喜欢较短的 但是 我只想真正深入了解本质细节 我可能一直在创建有缺陷的代码 并且我不想在网络上贡献和传播懒惰完成的代码 所以告诉我 它们之间有哪些显着的优点 缺点 或者是 就像冰淇淋一样 不同
  • 如何使用 C# SDK 连接到 facebook 并调试 facebook 应用程序

    我真的很努力地试图找到一些真正适用于基础知识的启动和运行的东西 即使是 SDK 附带的教程应用程序似乎也必须上传才能工作 因此没有简单的方法在本地调试和测试它 有人有我可以使用的工作示例的链接吗 Cheers 这就是我目前在我的 aspx
  • 如何使用python自动将基于CSV的表创建到postgres中

    我是一名新的 Python 程序员 尝试使用 python 脚本将示例 CSV 文件导入到我的 Postgres 数据库中 我有一个名为abstable1的CSV文件 它有3个标题 Absid 名称 编号 我的一个文件夹中有很多这样的文件
  • 在 virtualenv 中通过 pip 安装 PyGObject [重复]

    这个问题在这里已经有答案了 我实际上正在将旧的 django 应用程序从 python2 7 升级到 python3 4 通过 pip 安装 pygobject 时 出现此错误 Collecting pygobject Using cach
  • Netbeans 将 css 变量显示为错误

    当我使用 css 变量时 我的 Netbeans IDE 显示错误 例如 这行代码将返回错误 root main bg color dad66f title color var main bg color 我在网上找到了这个解决方案 htt
  • 尽管+ geom_line() 图表中没有线条

    我已阅读文档 我认为我的代码应该是正确的 但输出中的点之间仍然没有线条 怎么了 x 轴是离散的 y 轴是连续的 My code point sqrmPrice lt ggplot overview df aes x areaSize y s
  • Maven 依赖类型 ejb 与 jar

    有什么区别
  • jQuery CouchDB - 视图的过滤键

    我正在使用与 couchdb 捆绑在一起的 javascript 库来查询数据库 附带说明一下 这里很好地概述了它提供的功能 并提供了很多很好的示例 http bradley holt com 2011 07 couchdb jquery
  • 根据条件添加 vue 指令

    是否可以根据条件设置指令 我有一个 粘性 指令来使元素粘在屏幕上 我有一个正在使用的社交分享组件
  • 用户表中发生“数据操作操作在此视图上不合法”

    当我尝试在属于我正在使用的用户的表上插入值时 会发生此错误 SQL Error ORA 01732 data manipulation operation not legal on this view Cause Action 在人们所说的
  • .htaccess php_value include_path 不起作用

    我在当地有一个小项目 我在 Windows 下使用 XAMPP 工作 我的文件目录结构是 根目录 C xampp htdocs routes Under this folder I have my bootstrap php with th
  • python 中的最小堆

    我想通过定义自定义比较函数将一组对象存储在最小堆中 我看到有一个 heapq 模块作为 python 发行版的一部分可用 有没有办法在此模块中使用自定义比较器 如果没有 其他人是否构建了自定义最小堆 两个选择 除了 Devin Jeanpi
  • Android Studio 点击 Android 设备监视器时出现错误

    每当我单击 Android 设备监视器时 我都会在 android studio 中遇到此错误 Monitor An error has occurred See the log file C Users
  • 稍后如何附加到正在运行的 Docker 容器?

    我想简单地启动一个 docker 容器来执行一些 java 代码 最终启动 JBoss 这工作正常 只是我不知道如何再次连接到容器并返回到 bash 提示符 这就是我启动容器的方式 docker run i t p 80 80 v tmp
  • 如何在powershell中使用system.tuple?

    只是出于好奇 这不是 我必须拥有它 而是如何在 powershell 中使用 system tuple 类声明元组 我正在使用 powershell exe config 加载框架 4 0 但无法创建元组 尝试这个 PS C ps1 gt
  • igraph 中的颜色特定节点

    我正在尝试为节点 6 和 7 着色 无论从对象 d 中选择什么字母 g lt graph from literal 1 2 3 4 5 6 7 Rename sum up all the vertices d lt c a b c d e
  • Android NDK 构建,方法无法解析

    我有一个带有本机代码的 Android 项目 我可以通过调用从命令行构建本机代码ndk build命令没有错误或警告 但是当我在ADT中打开它时 它显示以下错误 错误信息 Method CallStaticIntMethod could n
  • 基于组件的游戏设计中的共享字段

    我认为这是使用 XNA 在 C 中完成基于组件的游戏引擎之前的最后一个逻辑飞跃 我定义了实体类和抽象组件 我的问题出现在我的 EntityFactory 中 当我想创建一个新实体时 我将 EntityType 枚举传递给工厂中的静态方法 然