Entity component system: efficient component retrieval?

Started by
13 comments, last by RobM 10 years, 3 months ago

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
Advertisement

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 [twitter]devmoon[/twitter]
Homepage http://devmoon.se
Stream http://twitch.tv/devmoon

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?

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

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

soundcloud.com/herwrathmustbedragons

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

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.

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.

"So there you have it, ladies and gentlemen: the only API I’ve ever used that requires both elevated privileges and a dedicated user thread just to copy a block of structures from the kernel to the user." - Casey Muratori

boreal.aggydaggy.com

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.


Where are we and when are we and who are we?
How many people in how many places at how many times?

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?

This topic is closed to new replies.

Advertisement