我基于组件的游戏引擎的GameObject
抽象实现如下:
游戏物体
我一直在阅读基于组件的设计,引起我注意的一件事是由于缓存导致数组的线性遍历很快,所以这让我决定使用基本数组来保存实体/游戏对象。
现在引起我注意的另一件事是,一些资源将组件与游戏对象分开。他们所做的是在实体经理内部有一张地图。地图将游戏对象作为键,将组件数组作为值。在这种情况下,A GameObject
只有一个ID。
是否有一个优势(性能和/或设计明智)让地图将游戏对象附加到组件而不是在GameObject
类中包含组件?
此外,GameObject
将从Pool
对象汇集(回收),以避免频繁的内存分配。
答案 0 :(得分:3)
在大多数游戏组件系统中,您需要阵列和词典(地图)。
对于线性遍历(即在更新期间),数组用于枚举对象和组件。
对于按ID,名称或其他属性查找,可以使用一个或多个字典按相应类型查找组件。这通常需要在阵列上进行线性搜索会导致明显的性能损失。
此外,可能还有其他数组存储按组件排序的游戏对象,例如具有特定组件(如CombatComponent)的游戏对象数组。
通常这将包装在一个类中,允许您通过索引访问组件(或游戏对象),枚举它们,或通过ID等某些条件获取它们。班级'然后可以随着时间的推移更新实现,以通过更高的内存使用量来获得更好的性能来加速对特定组件的访问(即引入一个额外的字典来按启用状态索引组件,或者按空间位置引入游戏对象)。
简而言之:总会有权衡。开始使用额外的词典和数组主要是方便和性能问题,但它绝不是一个/或决定。
如果需要按顺序枚举对象,则默认存储实现应始终以数组开头。字典的主要问题是枚举的顺序可能会改变帧的帧,这在游戏中是必须避免的。
答案 1 :(得分:1)
这还取决于你制作的游戏类型。
根据我的经验,松散耦合的对象几乎总是表现得更好,因为内存分配很少发生,而引用对象通常分批发生,并且用于特定任务。我喜欢这种方法,因为它可以防止你搞乱大量的虚拟表和类层次结构。虚拟指针打破了代码缓存。所以在这种情况下,我将对象放在不同的管理器中,但是具有相同的句柄/ id,并且只是在相关的集合中运行。
如果涉及昂贵的可见性查询,将多个列表放在手边并且仅在必要时更新它们(例如时间片)通常会更便宜
另一种方法是使用具有父/子关系的链接列表仅构建相关对象(一种基于树的跳过列表)来构建依赖性遍历树。这很有用,因为有些时候你想要预先构建变换,或者遍历所有光发射器,或者首先通过碰撞检测和响应等运行所有对象。逻辑上,任何类型的“事件”都必须在你的然后可以通过链表遍历来翻译游戏世界。它可以为您节省管理人员,但它会创建大量的内存跳转和管理,以保持父/子的最新状态。
如果你可以对你的计算进行矢量化并获得100倍的加速,那么,这是查看对齐和打包的一个很好的理由。有一段时间,我们使用了一个小的对象缓存,只保留在内存中经常需要的那些位,例如转换等等。但实际上,在你到达之前,你最终会遇到这么多的isXYZ()调用改变,这不再是真正的回报。这个想法很好,当时有一些加速,但逻辑错综复杂到它变得毫无意义。
正确的说法当然是它取决于你必须处理的任务和对象或子集的数量。如果你不知道这一点,但你怀疑它可能失控,这取决于你的时间:如果相当多,松散耦合可能只是事情。额外的奖励是重构类型并没有真正影响你那么多。否则,你可能最好只将所有东西存放在一起并希望最好......