Entity-Component systems

Started by
55 comments, last by CrazyCdn 6 years, 4 months ago

I read some interesting literature describing Entity-Component systems:

GREGORY J.: Game Engine Architecture, 2nd Edition.

http://www.randygaul.net/2013/05/20/component-based-engine-design/

http://www.randygaul.net/2014/06/10/sane-usage-of-components-and-entity-systems/

and some GameDev links (which I removed due to the ugly and large widgets replacing the urls).

Though, I am still not 100% sure, the direction I want to go. I like Unity's representation in the editor, unfortunately Unity is close source. Though, Unreal's monolithic class hierarchy is nice as well since you can basically override every class as a user.

The Unity editor has a GameObject tab and a Component tab. The "GameObjects" represent the different kind of nodes in the scene graph. The "components" seem to be add-ons for the "GameObjects". Though, some overlap is possible since you can have a standalone Camera or an add-on Camera. At first this seems like a nice separation. But when looking to the hierarchies in their scripting API, most of these "GameObjects" and "components" are just inheriting their Component class anyway.

If one wants to represent this in code, the GameObject can have:

  • human readable name (string or hashed string)
  • guid
  • some flags, tags and layers
  • transform (I do not want separate transform component)
  • collection of component (pointers or ids)
  • some message/event passing utilities

Each Component has a way to access its associated GameObject. My scripts will be components as well containing some specific message handling methods that can be overriden.

Each System will access the Components it needs.

That said, how are these Components stored at the Engine side? For memory coherence, I would expect to see something like a dynamic array per Component base type instead of per Component type since you can have an infinite number of components. I guess this Component base type must be specialized enough to avoid all types of casts?

🧙

Advertisement

Unity is actually reworking it's EC System right now.

You might want to have a look at this. Also, the code is open source. (Or it's going to be soon) :

 

3 hours ago, LifeIsGood said:

Unity is actually reworking it's EC System right now.

Interesting refactor, though for now I don't want to go to a complete SoA instead of AoS. That is a bit too data driven (which is problematic for encapsulation).

 

I am not specifically concerned with scripting alone. I want to put Components used by other Systems (such as audio, physics and graphics) in some collections as well. I probably will store these data by value. Though, what is the granularity of storing these values (i.e. how many collections)?

Furthermore, assume we have an infinite number of scripts (each with their own type extending a base class), how could you implement the equivalent of Unity's GetComponent method: T *Component::GetComponent< T > without using casts? How would you even now how to cast? The GameObject only has some pointers to abstract Components. If you want all SpotLights, you can simply look in your scene's SpotLightComponent buffer to find some potential matches. But what if you want a specific ScriptComponent?

🧙

4 hours ago, matt77hias said:

Interesting refactor, though for now I don't want to go to a complete SoA instead of AoS. That is a bit too data driven (which is problematic for encapsulation).

 

I am not specifically concerned with scripting alone. I want to put Components used by other Systems (such as audio, physics and graphics) in some collections as well. I probably will store these data by value. Though, what is the granularity of storing these values (i.e. how many collections)?

Furthermore, assume we have an infinite number of scripts (each with their own type extending a base class), how could you implement the equivalent of Unity's GetComponent method: T *Component::GetComponent< T > without using casts? How would you even now how to cast? The GameObject only has some pointers to abstract Components. If you want all SpotLights, you can simply look in your scene's SpotLightComponent buffer to find some potential matches. But what if you want a specific ScriptComponent?

If you don't mind me asking, why are you choosing the ecs model over entity-component model if you're not going to take certain optimizations like DoD and etc? You will be creating a more complicated system without the benefits of cache coherency. Unity and UE4 are currently using an entity-component model. A benefit is that it's much simpler to write code and encapsulate, but it becomes more difficult to multithread it. To deal with the issue of multithreading, Unity has chosen to switch to an ecs model. I'm currently maintaining the entity-component model, but using messaging to handle multithreading.

10 hours ago, AxeGuywithanAxe said:

ecs model over entity-component model

What is the difference between an Entity-Component-System and an Entity-Component Model in your terminology? Nor my Entities or Components contain methods like do this or do that apart from the scripts? My rendering system retrieves the data from the components and performs the rendering based on that data; so quite DoD.

I am still doubting whether a SpotLight is the most specialized component? Assume it is, we can store SpotLights by value in some collection. If not, the user can extend the behavior (within the realm of engine support) via inheritance.

🧙

ECS means you're using tables of data like in the relational model. 

EC means your using composition like in OOD. 

52 minutes ago, Hodgman said:

ECS means you're using tables of data like in the relational model. 

EC means your using composition like in OOD. 

Than I rather like the terminology of Game Engine Architecture: The Object Model architecture can be object-centric of property-centric (i.e. data tables).

Apparently, the object-centric approach encapsulates attributes and behaviors. That latter is definitely not something that I want. My components are represented as stupid containers where the attributes are encapsulated but no behavior is added (except for scripts since their behavior is actually their data). The property-centric approach encapsulates only the attributes whereas the behavior is implicitly defined by the attributes.

On the other hand, what I actually intend to do falls under object-centric.

Generic Components (pp. 885-886): The root game object is provided with a generic list of components which all derive from a common base class (to retrieve type information and pass events/messages).

 

 

🧙

I provide some pseudocode:


class Entity {
    
    // Identification
    U32 m_guid;
    string m_name;
    vector< string > m_tags;
    vector< string > m_layers;
    
    // State
    bool m_active;
    
    // Components
    UniquePtr< TransformNode > m_transform;
    vector< Component * > m_components; ~~~> Accessible from the scripts without casting???
}

class Component {

    // Owner
    Entity *m_entity;
    
    // State
    bool m_active;
}

class Scene {

    // Entities
    vector< Entity > m_entities; ~~~> All systems will access the TransformNode component

    // Component collections
    vector< AudioEmitter > m_audioemitters; ~~~> AudioSystem
    ...
    vector< BoxCollider > m_boxcolliders; ~~~> PhysicsSystem
    ...
    vector< Spotlight > m_spotlights; ~~~> RenderingSystem
    ...
    vector< UniquePtr< Script > > m_scripts; ~~~> ScriptSystem (note the pointer)
}

Not really sure how frequently a user wants to remove Components from an Entity, so this is a potential bottleneck. Idd. for searching a specific Component (e.g. via a script).

 

Furthermore, assume I want to visualize the tree hierarchy in an editor, then I need to know the type of each Component to access its attributes or:

  • Each Component should have a virtual method DrawUI. But that makes no sense.
  • Each Component should have a message handler for visualization purposes. But that makes no sense either. Furthermore, this is conceptually pretty similar to the first solution.
  • Each Component should be accessible by a Visitor. The editor is then capable of using a visitor for showing the UI.

🧙

I think i'm starting to understand what you are saying, but it seems like you've also noticed that you hit one of the problems of ECS . Which is leveraging the "system" part while still maintaining the benefits of certain practices like inheritance. 

 

On 12/2/2017 at 6:43 AM, matt77hias said:

That said, how are these Components stored at the Engine side? For memory coherence, I would expect to see something like a dynamic array per Component base type instead of per Component type since you can have an infinite number of components. I guess this Component base type must be specialized enough to avoid all types of casts?

The issue with this approach, is that it isn't exactly cache coherent. You are still jumping through memory to access the components, so in what way have you actually benefited? This and a few other issues , for instance not having an easy way to update all of a parent entity's components prior to my own, is why I chose to go with the entity component model in which components contain logic. 

53 minutes ago, AxeGuywithanAxe said:

The issue with this approach, is that it isn't exactly cache coherent.

For the scripts, I indeed use pointers to exploit polymorphism. The user is capable of creating an infinite number of different scripts. For the other components, it is possible to store them by value to exploit cache coherence. The user is not capable of creating such components: they are defined by the engine itself

 

56 minutes ago, AxeGuywithanAxe said:

for instance not having an easy way to update all of a parent entity's components prior to my own

.My TransformNode constitutes the scene graph. Though, you are indeed right that if you use some information not contained in the local part of the TransformNode (for example something relative to the world), the correctness depend on the order of executing the scripts.

Game Engine Architecture recommends using buckets, but this is way from general (Naughty Dog uses only 3 buckets).

1 hour ago, AxeGuywithanAxe said:

The issue with this approach, is that it isn't exactly cache coherent. You are still jumping through memory to access the components, so in what way have you actually benefited? This and a few other issues , for instance not having an easy way to update all of a parent entity's components prior to my own, is why I chose to go with the entity component model in which components contain logic. 

So based on the above, is it correct that you are only concerned with:


vector< UniquePtr< Script > > m_scripts; ~~~> ScriptSystem (note the pointer)

because apart from the scripts, all my other components' "behavior" is to get, set or bind some data on behalf of some 3th party.

 

1 hour ago, AxeGuywithanAxe said:

is why I chose to go with the entity component model in which components contain logic

But how does this look like from the perspective of the Entity? One common Component base class (OO way of doing things) or a "sort of database" (property/table way of doing things)?

🧙

This topic is closed to new replies.

Advertisement