I'm writing a little Entity Component System (ECS) in Javascript (Typescript specifically) and it currently works, but I was wondering if it could be more efficient under the hood. The way an ECS works is that entities are basically just bags of components. So, a player entity might have a HealthComponent
, PositionComponent
, SpriteComponent
, etc. Then you can create a RenderingSystem
that queries all entities with a PositionComponent
and a SpriteComponent
and then it renders them. Like this:
for (let entity of scene.query(CT.Position, CT.Sprite) {
// draw entity
}
To make this efficient when querying, rather than iterating through every entity in the scene to see if it has a Position
component and a Sprite
component every time, what we instead do is that cache it after the first query call and then keep it updated, so every query call can just return us the list of entities, rather than iterating through the entire list of all entities first each time.
So, as an example, the cache might look like this:
{ "6,1,20" => Map(1) }
{ "2,3,1,6" => Map(1) }
{ "2,3" => Map(31) }
{ "9" => Map(5) }
{ "2,8" => Map(5) }
{ "29,24,2" => Map(5) }
// etc..
The numbers refer to the value of the enum values like CT.Position
, CT.Sprite
, etc. In this case, CT.Position
is 2 and CT.Sprite
is 3, and there are 31 entities that have those two components. So when querying all entities that have those two components, we can just return that list of entities, rather than computing it each time.
This all works, but it's not very efficient, because adding (and removing!) an entity to the scene is an O(n)
operation and also involves a lot of string splitting and concatenation. You need to iterate through every item in the cache to see if the entity's list of components is included by that entry.
Is there any way to improve this to be more like O(log n)
or preferably O(1)
? Let me know if this is all clear, or if there's any details that need to be clarified.
Here's a link to the Typescript Playground URL reproduction example