Jump to content

  • Log In with Google      Sign In   
  • Create Account

Entity component system: efficient component retrieval?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 vinnyvicious   Members   -  Reputation: 365

Like
0Likes
Like

Posted 04 January 2014 - 05:54 PM

So, my ECS right now is pretty simple. I have a GameObject class, which represents my entity, that contains a few helper methods. It also contains a hash set with all the components that specific game objects has. I have a few methods, like GetComponent, GetComponents, etc. I also have a Scene, which has all GameObject instances (stored in a hash set as well, with the gameobject name and instance) and other scene data (transition in, out, etc.). My AbstractScene contains a method for getting all components of a specific name, from all game objects in that scene. Something like this:

 

scene.getComponents('position'); // returns a list of all components with the name "position", from all GameObject in the scene.

 

This method is called from the Behaviors. PositionBehavior is responsible for processing all the "position" components. It's the system.

 

My question is: how do i optimize this? Having to iterate on all GameObjects and find all components, creating a new list and returning seems pretty cumbersome and inefficient. And i'm doing this on every update. My architecture is something like this:

  • Start first scene
  • Game loop
    • Call the render() method on the Scene object
    • Call all Behaviors that are Renderable
    • Call the update() method on the Scene object
    • Call all Behaviors that are Updateable
    • Call PhysicsBehavior


Sponsor:

#2 Kristoffer   Crossbones+   -  Reputation: 839

Like
1Likes
Like

Posted 04 January 2014 - 06:08 PM

Does your PositionBehavior have a list of all Positions components? if so then it can update them without getting them from the object itself.

 

This is how I do my component updates.


Blekinge Institute of Technology
Twitter @devmoon
Homepage http://devmoon.se
Stream http://twitch.tv/devmoon

#3 vinnyvicious   Members   -  Reputation: 365

Like
0Likes
Like

Posted 04 January 2014 - 07:44 PM

Is your PositionBehavior a singleton, then? In my case, i add components to my entities via addComponent method, which is a method of the GameObject class. How do you link your components to the entities?



#4 Strewya   Members   -  Reputation: 1432

Like
1Likes
Like

Posted 05 January 2014 - 01:29 AM

Why would it have to be a singleton?

When adding a component to a GameObject, add it to both the object, and the system responsible for updating it, keeping only a reference/pointer to the component in the system. If a GameObject gets deleted, make an event to each system telling it about the deletion so it can remove that objects' component from the list/vector/hashmap/whatever.


devstropo.blogspot.com - Random stuff about my gamedev hobby


#5 NoAdmiral   Members   -  Reputation: 511

Like
0Likes
Like

Posted 05 January 2014 - 01:52 AM

I do all of my component updating through the systems themselves. This makes sure that only those entities that have said component get updated and the order of updating. If there are messages to be handled, it's all done during that system's update. 

 

My systems each contain a Dictionary<ulong, Component> (I'm using C#, so substitute whatever method you use) which holds the entity id (the ulong) and the component with the data associated with that system. This way, you shouldn't have to iterate over all of your entities because you already have a list of each component and the entity to which it belongs. I don't think, other than adding/removing a component, that I ever actually use the Entity objects themselves (I use the EntityManager class to handle messages, because each message type may have to be sent to multiple systems, so I just use it as a hub to send the messages to all applicable systems, though this may not be the most efficient way of handling this business). 


Inspiration from my tea:

"Never wish life were easier. Wish that you were better" -Jim Rohn

 

herwrathmustbedragons.tumblr.com


#6 vinnyvicious   Members   -  Reputation: 365

Like
0Likes
Like

Posted 05 January 2014 - 06:05 AM

How are your entities aware of the systems, then? Where do you add a component to a game object? I have an "addComponent" method on my Entity class, but that requires all systems to be singletons, in your case, or have some kind of complex DIC setup. Also, how do you track from which entity is which component? 

 

In my case, there's this relationship hierarchy:

 

  • Behavior (System)
  • Scene
    • Game Objects
      • Components

Edited by vinnyvicious, 05 January 2014 - 06:06 AM.


#7 haegarr   Crossbones+   -  Reputation: 4309

Like
2Likes
Like

Posted 05 January 2014 - 06:25 AM

In general (because I don't know how NoAdmiral does things in particular):

 


How are your entities aware of the systems, then?

Entities are not aware of sub-systems, perhaps besides one that generates entity IDs and store entities. In your case those sub-system is part of the Scene.

 


Where do you add a component to a game object? I have an "addComponent" method on my Entity class, ...

With the sub-system approach an entity need not be anything more than an ID. You can, of course, still have an explicit entity, e.g. to store a collection of all of its components, if you wish. But in fact the components are added to the belonging sub-systems with the entity's ID as reference.

 


... but that requires all systems to be singletons, in your case, or have some kind of complex DIC setup.

Singletons? No! They usually need to be unique in a context, yes, but that does not mean they they need to be implement as singletons. E.g. in your case it would be possible that the Scene holds all the sub-systems' instances.

 


Also, how do you track from which entity is which component?

At the moment you have a map of all components of a particular entity with the component type as key. No problem to make a map of a particular component type with the entity ID (may even be the address of the entity instance) and store that in the belonging sub-system.



#8 Boreal Games   Members   -  Reputation: 812

Like
0Likes
Like

Posted 05 January 2014 - 09:45 AM

Check out the articles in my signature for how I do my components.  They're basically just arrays of components (one per type) and another array of component masks.  An entity is the aggregation of all the elements at a given index in the arrays, where the component mask describes which components "exist" (are turned on).

 

It's cache friendly and requires no memory allocation past the initial allocation of the arrays.



#9 noizex   Members   -  Reputation: 865

Like
0Likes
Like

Posted 05 January 2014 - 11:32 AM

Just for the record I haven't read post above (Boreal Games) when I wrote mine - now I did and it seems to be similar in approach to what I wrote in 2). 

 

I can think of at least 3 approaches to this:

 

1) Registering components in corresponding systems so you don't have to query scene for objects that have component "Position" - system already has list of these components and its updated when object is added/removed from the scene. This is probably good approach if you plan to have hundreds of thousands of objects. Here you need to decide how component knows which system may be interested in having it - this may work on a listener basis where systems "listen" for certain components being either added/removed from object, or objects with components being added/removed from scene. 

 

This approach requires that removing/adding is properly handled so you don't end up with systems keeping components that were removed, or their owners no longer exist.

 

2) Querying objects that meet component criteria, based on some "key". In my system I'm using a uint64 bit mask - when component is added to object, this objects sets a mask for component's family (family is a group of same-type components, for example Renderable is family sharing common interface that can be derived from to create TerrainRenderable etc.). When component is removed, it clears the mask. This allows me to know exactly what component types belong to a given game object - I don't have to retrieve exact component when I just need to gather objects that have for example Renderable and Spatial component.

 

When adding component to object:

 

m_CompMask |= static_cast<uint64_t>(family);

When checking if object has certain components, for example Comp::RENDERABLE and Comp::SPATIAL:

 

bool HasComponents(uint64_t mask)
{
      return (m_CompMask & mask) == mask;
}

if (obj->HasComponents(Comp::RENDERABLE | Comp::SPATIAL))
{
}

This way you can iterate over scene objects quite efficiently checking only bitmask. This still won't scale too well if you plan on having really A LOT of objects.

 

I use the second approach for scene on client-side where I don't really plan to have more than maybe few hundreds to a couple of thousands objects at any time. But for something like managing all game objects on some online game server side, this can easily go up to hundreds of thousands of objects and may be too slow - this is where I'd look into first method and register components in systems that require them.

 

3) System-ownership where systems are owners of components - if they own them, they already know about them so no need to query smile.png This may be best considering cache friendliness and speed, but gets complicated if there is system that works on more than 1 component - who owns such component then? Because of this I haven't tried this approach. In my case, object owns its components, and scene queries its objects for certain criteria. If I have render system that requires both - SPATIAL and RENDERABLE components on object, it can ask scene for them easily.


Edited by noizex, 05 January 2014 - 11:38 AM.


#10 vinnyvicious   Members   -  Reputation: 365

Like
0Likes
Like

Posted 06 January 2014 - 07:19 AM

Although i find the bitmask approach very elegant and efficient, it's limitations appear too quickly, specially since i'm trying to create a generic engine for my games. After writing so much tight and not very reusable code, i'm trying to abandon those vices. I read in many articles that the system can have an std::vector with the component instance and the entity ID, and to optimize removal, use move.

 

Do you guys agree with that? 



#11 larspensjo   Members   -  Reputation: 1538

Like
0Likes
Like

Posted 06 January 2014 - 05:26 PM

There is an example of an ECS implementation, which is very efficient. I think it is based on a similar idea as noizex #2, but without a hard 64-bit limitation?

 

Look at the tutorial on the front page, it is quite easy to follow. It takes away most of the implementation details from the user.


Current project: Ephenation.
Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

#12 RobMaddison   Members   -  Reputation: 694

Like
0Likes
Like

Posted 07 January 2014 - 01:14 PM

Check out the articles in my signature for how I do my components.  They're basically just arrays of components (one per type) and another array of component masks.  An entity is the aggregation of all the elements at a given index in the arrays, where the component mask describes which components "exist" (are turned on). It's cache friendly and requires no memory allocation past the initial allocation of the arrays.


I'm not sure I agree that components must be data-only and you also specified that systems operate only on groups of components when they all exist. Not sure what you meant by that but doesn't that negate the plug-and-play nature of ECS?

#13 Servant of the Lord   Crossbones+   -  Reputation: 19499

Like
0Likes
Like

Posted 07 January 2014 - 01:49 PM

The 'component mask' is sometimes also called a 'key':

http://gamedev.stackexchange.com/questions/31473/role-of-systems-in-entity-systems-architecture/31491#31491

http://gamedev.stackexchange.com/questions/4898/are-there-existing-foss-component-based-frameworks/4966#4966


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#14 Boreal Games   Members   -  Reputation: 812

Like
0Likes
Like

Posted 07 January 2014 - 02:31 PM

 

Check out the articles in my signature for how I do my components.  They're basically just arrays of components (one per type) and another array of component masks.  An entity is the aggregation of all the elements at a given index in the arrays, where the component mask describes which components "exist" (are turned on). It's cache friendly and requires no memory allocation past the initial allocation of the arrays.


I'm not sure I agree that components must be data-only and you also specified that systems operate only on groups of components when they all exist. Not sure what you meant by that but doesn't that negate the plug-and-play nature of ECS?

 

 

Nope, my system is perfectly plug-and-play.  The systems read the component mask to determine if they should act upon the component data for that entity.  If you're "adding" or "removing" a component, you're just modifying the component mask to change the visibility of the component to the systems.



#15 RobMaddison   Members   -  Reputation: 694

Like
0Likes
Like

Posted 07 January 2014 - 02:51 PM

Check out the articles in my signature for how I do my components.  They're basically just arrays of components (one per type) and another array of component masks.  An entity is the aggregation of all the elements at a given index in the arrays, where the component mask describes which components "exist" (are turned on). It's cache friendly and requires no memory allocation past the initial allocation of the arrays.


I'm not sure I agree that components must be data-only and you also specified that systems operate only on groups of components when they all exist. Not sure what you meant by that but doesn't that negate the plug-and-play nature of ECS?
 
Nope, my system is perfectly plug-and-play.  The systems read the component mask to determine if they should act upon the component data for that entity.  If you're "adding" or "removing" a component, you're just modifying the component mask to change the visibility of the component to the systems.
I see that makes sense now




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS