实体组件系统-如何实现对象的变换?


11

在为引擎设计实体组件系统时,我在存储和检索特定类型的组件方面遇到了一些麻烦。

首先,让我澄清一下我将在此问题中使用的一些术语:

  • 我将“ 组件 ”称为一种数据结构,用于存储特定系统的相关数据。
  • 我称“ 系统 ”为方法和数据结构的聚合,它利用组件来更新与用户的游戏状态/界面。
  • 实体 ”基本上只是一个ID,用于检索游戏逻辑中的特定组件并修改其数据。

每个系统都拥有其组件类型(例如Physics-> PhysicsComponent,AI-> AIComponent,Rendering-> RenderingComponent)的(ID映射)数组,因此它可以有效地遍历数据。

但是,并非所有组件都专门由系统拥有。例如,“变换”组件存储对象的位置,旋转和比例。它是实体最重要的部分之一(Unity甚至使它成为强制性的),因为它被许多系统使用,例如物理,AI,渲染等。

这几乎就是我面临的问题。由于其他许多系统都使用了Transform,因此我应该如何为每个组件检索一个?我看到的一种可能的解决方案是使每个组件存储自己的实体ID。这样检索任何组件很容易,但是效率不高,而且它与组件的概念相反,后者是孤立的独立数据束,不知道其他任何组件。

是否有解决此问题的正确方法?变形应该成为一个组成部分吗?


3
+1代表“首先,让我澄清一下我将在此问题中使用的术语:”
Vaillancourt

我希望在此站点上看到更多这类问题。+1
S.TarıkÇetin'Apr 10'17

只需将所有组件存储为全局变量即可
Miles Rout

Answers:


2

这是一个相当广泛的问题,其答案在很大程度上取决于您的体系结构。但是,我将尝试给您一个一般性的答案。

您的物理和渲染系统当然需要进行转换,但是AI系统则不需要。因此,将转换封装到它自己的组件类中是有意义的。所有这些感兴趣的系统都将使用相同的数据,因此,对于实体而言,具有指向转换对象的指针或存储在其他位置的转换对象的ID是有意义的。

如果选择后一种解决方案,则每个对转换感兴趣的系统都将需要访问存储转换对象的任何位置。

如果选择前者,那么每个系统所需要做的就是访问实体本身,并请求转换。

在前一种情况下,问题就变成了如何在不违反OOP规则的情况下授予访问存储以转换到每个系统的权限(如果您关心此类事情)。

后一种情况没有这种问题,但是需要更改您的实体对象设计以存储指向对象的指针而不是组件对象的ID。

我个人的喜好是设计实体类以存储指向组件对象的指针,因为它简化了许多设计问题。这样,每个需要转换的系统都可以向实体请求该转换,如果不需要,则将其忽略。但是,这确实带来了指针固有的计算开销,这是缓存未命中的代价。

看看此ECS概述参阅以了解更多信息。

归根结底,由您决定哪个对您更重要:开发的便利性或性能。

最后,我要指出的是,您的问题是ECS支持者所考虑的设计问题的一个很好的例子,并且没有确定的解决方案。


感谢您的建议。不过,我有一个问题:为什么AI系统不需要对象的位置?
CRefice

您混淆了位置(3个浮点的向量)与平移(根据位置向量构造的变换矩阵)。转换矩阵由平移,旋转和比例转换构成。尽管您当然可以从中提取位置矢量,但这远远超出了AI系统所需的信息。不过,就我个人而言,我会将位置,方向和大小分开到各自的组件中,并使用它们来创建和更新Transform。
伊恩·杨

@IanYoung分离它们可能弊大于利,如果您发现比单独定位或定向需要更多的位置和定向,则可能有害。在那种情况下,将位置和方向数据属性放在单个组件中可以提高缓存性能。
罗斯(Naros)

1
我的首选是将位置,方向和比例这三个要素合并为一个组件,如果特定子系统仅需要一个位置或方向,我建议复制数据并在游戏循环中明确定义的点进行同步。
Naros

@Naros是的,这就是我的意思:两个组件,变换和(在我的框架中)SpatialData,其中包含位置,速度,方向和角速度。位置和方向用于构造和更新Transform。
伊恩·杨
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.