ayebear / es

An easy to use, high performance, C++14 "Entity Component System" library.
MIT License
12 stars 2 forks source link

Improve World::query() performance #7

Closed ayebear closed 9 years ago

ayebear commented 9 years ago

Currently, query() is O(n) and does a few full iterations to build up a vector with all matching entities. This is inefficient especially for a function that is used multiple times per frame.

The World should keep some kind of index around which gets updated when adding/removing components. It would then do some hash or lookup in this table to get a reference to a list of all entities with those components.

ayebear commented 9 years ago

Note: Since the last few commits, components now store their owner ID, so you can write loops like this instead of using query(), which provides better performance in almost all cases:

for (auto& pos: world.getComponents<Position>())
{
    auto ent = world.from(pos);
    auto vel = ent.get<Velocity>();
    auto sprite = ent.get<Sprite>();
    auto rot = ent.get<Rotation>();
    if (vel && sprite && rot)
    {
        ...
    }
}

The reason this is faster, is because there will always be the same amount or less instances of a specific component than entities. The query() method loops through all entities every time, where with this you can pick the least common component to optimize the performance.

Update: query() could just be changed to use this new method internally! That way they'd end up being very close in performance. I will try this and see how well it works, to simplify the syntax back to this:

for (auto ent: world.query<Position, Velocity, Sprite, Rotation>())
{
    auto pos = ent.get<Position>();
    auto vel = ent.get<Velocity>();
    auto sprite = ent.get<Sprite>();
    auto rot = ent.get<Rotation>();
    ...
}
ayebear commented 9 years ago

Update: Even better! The query() method could check ALL component types passed in, and find the smallest array of components! Then, it would use that one to iterate through and return back the result set. This will be faster than the manual getComponents method in many cases where you aren't sure which is the best component to use, plus the syntax is more consistent.

ayebear commented 9 years ago

This has been improved enough from the last commit.