首页 > 解决方案 > 如何在 ECS 游戏中处理重复数据,以及有关 ECS 的更多一般问题

问题描述

我正在阅读关于 ECS 的文章,这些文章显然非常适合开发游戏。

我遇到了一个问题,或者一个问题,我会举例说明这个(这正是我遇到的问题)。

我有多个组件Boss, Minion, Player, Weapon, Name. 首先,我namePlayer组件中添加了一个字段。但是由于这些组件中的每一个都可以命名,所以我很想将它模块化并创建一个Name组件。大多数系统不会以相同的方式使用该名称,但有些会,主要是DebugSystem.

事实上具有组件的实体Player不能具有Name组件,但应该。我怎样才能轻松处理这个?

那是 :

理想情况下,该名称可以在具有名称的任何组件之间共享。它让我想起了 OOP 中的钻石问题,但 ECS 不是部分创建来解决这个问题的吗?

问题 1) ECS 中是否有标准方法来处理这个问题,或者应该由最后CreateEntity()添加缺失组件的函数手动处理?

关于 ECS 的其他一般问题:

我从继承Entity类开始,做生产链,如果我正确理解了原理(类本身并不重要,但它会自动创建组件)。然后我创建了其他一些实体类,但最终它们实际上可能只是组件。最后我什至不知道 Entity 类是否应该是可继承的。

问题 2)实体类在 ECS 系统中是否从未被继承?

在很多介绍文章中,他们并没有谈到组件之间的交互,但是在q/a论坛中,他们通常会提出一个事件驱动的系统来解决问题。

问题 3)事实上,ECS 模式是否与消息系统模式不可分离,应该一起使用(至少在大多数情况下),或者是否有纯粹使用 ECS 模式的解决方案?一些答案说事件完全破坏了 ECS 的优势,另一些人则建议这样做。

问题 4)组件可以包含指向其他组件的指针吗?组件可以包含指向其他实体的指针吗?我知道大多数答案都说它只是一个工具,没有什么不好的,但我想保留 ECS 的优势,而不违背它的原则。

问题 5)系统可以有任何数据吗?我没有找到任何关于它的东西。我正在考虑一个基于回合的游戏,我必须在其中存储回合数。因为数据不是一个具体的组件(它是系统本身的一些数据),所以我很想 1)GameData在一些像全局游戏状态一样的实体中创建一个单例组件 2)将数据放入TurnSystem,假设一次只能玩一个游戏。

标签: entity-component-system

解决方案


如果在关键循环中很少访问名称字段,我通常会认为将其放入自己的Name组件中是不费吹灰之力的。它是最灵活和最高效的解决方案,因为关联的数据是冷的(热/冷场拆分)。如果您将名称字符串字段添加到多个组件类型,这将增加从其中一个组件到下一个组件的步幅,并且更少的组件将适合您的关键系统循环中的缓存行。

问题 1) ECS 中是否有标准方法来处理这个问题,还是应该由函数 CreateEntity() 手动处理,最后添加缺少的组件?

If all entities require a name field, I would err towards your first solution and just add it automatically when entities are created. You might even assert to make sure that name components are never removed from an entity prior to its complete removal if you want to guarantee that this name component is always available.

Question 2) Is the Entity class never inherited in the ECS system ?

I don't know about 'never' but I would strongly lean against mixing inheritance into an ECS at entity or component level. First, memory management becomes immediately much more complicated and difficult to optimize with respect to access patterns if you have to deal with polymorphic base pointers to variable-sized entity or component subtype pointees.

Question 3) Is, in fact, ECS pattern not separable from a Messaging System pattern, and should be used together (at least in most cases), or is there a solution purely with an ECS pattern ? Some answers say Events destroy completly the advantages of ECS, some others advise it.

Up to you. I find it generally more productive to lean on the ECS as much as possible, but it can be quite useful and practical to be able to push events to a concurrent queue while processing one or more systems.

Question 4) Can Components contains pointers to others Components ? Can Components contains pointers to others Entities ? I know that most answer says that it's just a tool and nothing is bad about it but I would like to keep the advantages of ECS without going to the opposite of it's principles.

Yeah, absolutely. It's difficult for me to imagine a case where you wouldn't do that since even a basic motion hierarchy with parenting would require parent/child links between entities/components. I tend to use 32-bit indices to halve the memory requirements on 64-bit architectures and also because the data structures I use can invalidate pointers but not indices. Yet that's probably going to be a common requirement in most nontrivial projects to link entities or components together in some fashion.

Question 5) Can Systems have any data ? I didn't found anything about it. I was thinking about a Turn based game, where I have to store the numbers of Turn. Because the data is not a concrete component (it's some data of the System itself), I am tempted to either 1) Create A Singleton Component GameData into some Entity that act like the global game state 2) Put data into the TurnSystem, with the hypothesis that only one game can play at a time.

You could try to cram the data into components accessed via the system but I think it's a lot more practical and pragmatic to allow systems to store some data, like a physics cache for a physics system if it's an internal implementation detail that's only relevant to it and doesn't need to get saved along with the scene.


推荐阅读