Search code examples
entity-component-system

How to handle duplicate data in an ECS game, and more general questions about ECS


I am reading articles on the ECS that apparently scales well for developping games.

I ran into a problem, or a question, I will illustrate this for the example (this is exactly the problem I encountered).

I have multiples components Boss, Minion, Player, Weapon, Name. First I added a field name into the Player component. But since every of these components could be named, I was tempted to modularize it and create a Name component. Most of the Systems will not use the name in the same way, but some will, mainly a DebugSystem.

The fact is an entity with a Player component can not having a Name component, but should. How can I handle this easely ?

That is :

  • I can create an Entity with component Name only.
  • When I create an Entity with the component Player, either the component Name already exists or should automatically created. If possible, getting directly the name inside another component with something like entity.GetComponent<Player>().name.

The name can ideally be shared between any component that has a Name. It remind me the diamond problem in OOP, but isn't ECS partly created to solve this problem ?

Question 1) is there a standard method in ECS to handle this or should this be handled manually by the function CreateEntity() that add missing components at the end ?

Other general questions about ECS:

I started by inheriting from Entity class, to make production chain, if I've correctly understood the principle (the class itself is not important but it create the components automatically). Then I created some others Entity class, but in the end they could be in fact just Components. Finally I don't even know if Entity class should be inheritable.

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

In many introduction articles, they don't speak about interactions between components, but in q/a forums, they usually put forward an Event-Driven system to solve the problems.

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.

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.

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.


Solution

  • If a name field is rarely accessed in critical loops, I would generally treat it as a no-brainer to put it into its own Name component. It's both the most flexible and most performant solution since the data associated is cold (hot/cold field splitting). If you added a name string field to multiple component types, that would increase the stride to get from one of those components to the next, and fewer of those components would fit into a cache line in your critical system loops.

    Question 1) is there a standard method in ECS to handle this or should this be handled manually by the function CreateEntity() that add missing components at the end ?

    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.