4

我正在编写一个轻量级游戏引擎,并且在为它做一些研究的同时,我遇到了许多令人信服的文章,它们提倡通过“组件集合”模型而不是“从具体类继承”模型来实现游戏对象。有很多优点:

  • 可以使用数据驱动设计技术组合对象,允许设计人员在不涉及程序员的情况下提出新对象;
  • 源文件依赖项往往更少,从而可以更快地编译代码;
  • 整个引擎变得更加通用;
  • 可以避免必须更改继承层次结构较高的具体类的不可预见的后果;
  • 等等。

但是系统的某些部分仍然不透明。其中主要是同一对象的组件如何相互通信。例如,假设在游戏中模拟子弹的对象是根据以下组件实现的:

  • 一些用于视觉表示的几何图形
  • 世界地位
  • 用于与其他对象碰撞的体积
  • 其他事情

在渲染时,几何图形必须知道它在世界中的位置才能正确显示,但它如何在对象中的所有兄弟组件中找到该位置?并且在更新时,碰撞体积如何找到对象在世界中的位置以测试它与其他对象的交集?

我想我的问题可以归结为:好的,我们有由许多组件组成的对象,每个组件都实现了一些功能。这在运行时工作的最佳方式是什么?

4

7 回答 7

1

追求此策略的另一个重要原因是能够从行为组件中组合对象的行为,从而允许您跨多个游戏对象重用行为。

因此,例如,您有一个具有以下属性的基本游戏对象类:burnablemovable、 a ​​live。默认情况下,每个都包含对 null 的引用。如果你想让你的对象可燃,设置:

object.burnable = new Burnable(object);

现在,任何时候你想烧一个对象,使用:

if (object.burnable != null)
{
   object.burnable.burn();
}

可燃行为将以您想要的任何方式修改游戏对象。

于 2008-10-15T15:55:22.967 回答
1

我已经看到(并尝试过)几种方法来实现这一点:

1)组件不存在于真空中,而是收集在“实体”(或“游戏对象”)对象中。所有组件都有指向其实体的链接,因此您的冲突可能会执行诸如 GetEntity()->GetComponent("Position")->GetCoords() 之类的操作(可能检查空向量等 - 详细信息取决于您的语言)重新工作)。

在这种情况下,有时将一些常见信息直接放在实体中会很方便(位置、唯一 ID、“活动/非活动”状态)——在制作“纯粹”和通用的东西和快速制作东西之间需要权衡和高效。

2)没有实体,只有组件(我将它用于我自己的轻量级游戏引擎)。在这种情况下,组件必须显式链接到其他组件,因此您的“碰撞”和“图形”可能会保留指向“位置”的指针。

于 2008-11-04T14:35:08.617 回答
1

可组合架构通常依赖于接口。组件然后是实现+数据,使设计人员能够重新使用具有不同数据的可用实现。例如使用火箭代码一次与火箭图形和一次与箭头图形。灵活性来自于能够在实际运行时之外“配置”这样的组合。

在运行时,对象通过接口接收和提供必要的信息。例如,一个对象将接收一个原点和一个参考方向来定位自己在世界中。对于实际绘制的东西,我假设一种图形上下文将被传递,并且基础设施负责为当前对象适当地对齐默认偏移/投影。

于 2008-10-14T18:18:24.990 回答
1

我一直发现Kyle Wilson 的博客是一个有趣的来源,来自与此相关的人,并且似乎给了它很多思考。特别是这个条目可能很有趣: http: //gamearchitect.net/2008/06/01/an-anatomy-of-despair-aggregation-over-inheritance/。这不是文章的重点,但基本上他所说的是他们(在开发“ Fracture ”时)有不同的层次结构。一个用于游戏对象,一个用于视觉表示的场景图。我个人认为这是一个非常合理的设计,但我不是该领域的专家。

于 2008-11-12T11:10:05.517 回答
0

是否可以将对象引用回 Game 对象?

这将允许通过返回到 Game 对象然后向下钻取到世界位置来找到世界位置。

于 2008-10-14T18:20:42.347 回答
0

我也在研究这个问题,并提出了一些既快速又非侵入性的解决方案。

拥有基于组件的应用程序的目的是您可以在运行时随时添加和删除组件,并且很少或没有耦合;组件可以在不知道彼此的情况下共存。

那么,“渲染”组件如何知道它应该在哪里渲染,或者更糟的是,它应该渲染什么?我的回答是每个兄弟组件都可以访问其容器(通常是游戏实体或游戏对象)持有的共享属性表

例如,假设一个游戏对象具有运动组件、渲染组件和角色组件

渲染组件向其容器请求名为“positionx”、“positiony”和“positionz”的属性(如果它是 3D 游戏),然后请求“rendermodel”属性。基于这些,渲染器组件在 positionx、positiony 和 positionz 处渲染 rendermodel 返回的属性。定位属性由移动组件更改,移动组件本身要求容器上的“速度”属性,而该属性又由字符组件根据键盘输入进行调整。

如果这些属性不存在,则在请求它们时创建它们并使用有效值(例如:0)进行初始化。

在我看来,组件永远不应该查询其他组件,因为它们必须被视为尽可能通用。

于 2011-04-16T19:07:14.910 回答
-1

听起来有点过度设计。通过使位置成为对象的抽象组件而不是基本属性,您可以获得什么?

但是,如果您真的想这样做,我想您可以设置一个依赖关系图,其中所有内容都明确连接。因此(例如)碰撞体积具有连接到位置组件输出的位置输入。看看 Maya 的内部结构,了解它是如何工作的。

但是,恕我直言,这看起来很像矫枉过正。

于 2008-10-14T18:20:20.320 回答