A small header-only C++ ECS library

“I haven’t made a post in a while. I should work on that,” I thought to myself. “Oh, I know! I’ll talk about the little library I made a few months ago!”

Well, I made a small entity-component-system library based on the wonderful “Evolve Your Hierarchy” article. It’s a single-header library under the MIT license and is built with modern C++ (minimum support is C++11, ideal is C++14). It’s built in the style of components are data-containers while systems act on entities with specific components. It is made to use any data structure as a component (though ideally components should be plain old structs), and has the option of either using RTTI or a custom type system. There’s even a simple event system for inter-system communication.

The goals of the ECS is to be small, easy-to-use, and expressive. For example, let’s say we have this component:

Note: The code in this post assumes RTTI is enabled. If it isn’t, some additional macros must be used for each component type. See here for more information.

struct Position
{
    Position(float x, float y) : x(x), y(y) {}
    Position() x(0.f), y(0.f) {} // components must have a default constructor

    float x;
    float y;
};

Next, we need a system to act upon this component:

class GravitySystem : public EntitySystem
{
public:
    GravitySystem(float amount = -9.8f)
        : gravityAmount(amount)
    {
    }

    virtual ~GravitySystem() {}

    virtual void tick(World* world, float deltaTime) override
    {
        // here's the meat - for each entity with the Position component, we can run a function (or lambda)
        // in C++14, we can even use 'auto' instead of writing out each type name for parameters!
        world->each<Position>([&](Entity* ent, ComponentHandle<Position> position) {
            position->y += gravityAmount * deltaTime;
        });
    }

private:
    float gravityAmount;
};

Now we just create the world, setup the system, and make an entity!

World* world = World::createWorld();
world->registerSystem(new GravitySystem());

// Let's make an entity!
Entity* ent = world->create();

// Give it a component - note that each entity can only have one of each type of component
ent->assign<Position>(0.f, 0.f); // you can pass arguments to the constructor of the component!

Now we can tick the world, for example in the main loop of a game.

world->tick(deltaTime);

And finally…

world->destroy();

Here’s a short list of other features the library supports:

  • Range-based for loops for iterating over entities (including only iterating over entities with specific components)
  • Full event system
  • Custom allocators
  • More lambdas!

The library isn’t particularly built for speed, but I’ll be doing an optimization pass over the code for both performance and memory handling soon. You can find the library here.

Leave a Reply