ECS-API is a ECS framework. It is build around 3 simple ideas:
- Optimised for space-time complexity
It is using the minimal storage space as possible and it using linear search. - No boilerplate on the user side
Althought the API itself has quite of boilerplate, it is not the case for the user.
This API is very straigforward to use but also has a very powerful and inexpensive implementation. - Flexibility in order to deal with different implementations
This ECS is actually a "EC", because the system are up to the user.
The API provides functions to add, remove, update, iterate, collect using idioms (any, all, not) the components associated to an entity, thus the entities and the components can be managed by any functions, aka systems, implemented by user side, they do not require any "base class" or whatever.
It is important to note that the entity data structure is a 32bit size, having a index of 24 bits and a version of 8 bits.
Whenever an already created entity got destroyed, when a new one is created, the API will use the "spot" left free by the previous one, re-using the same index but incrementing the version.
When the version reach the limit, simply wrap around and restart.
The actual API can be found here: ECS
While here there are some examples of usage.
In order to use, just include the main header and use the namespace ecs
and you are good to go!
Is working on 64 bit platform only due the usage of _BitScanForward64 (or __builtin_ctzll unix systems)
Due the nature of the library and where you can link this against to, you have to add the processor ECS_EXPORTS to avoid linkage error.
This library does not use precompiled headers
A way is cloning this repository in your project, but in that case need to remove/exclude from your project everything apart the folder ECS-API/ECS, but is not very pretty, because git will notice the change.
A nice way instead, is simple to download or cloning this project somewhere locally and copy inside your own project the ECS folder containig ONLY the implementation of the API, the ECS.
Anyway is up to you, is still very self contained library!
There are some steps to do at the beginning and some step to perform at the finalization. These are:
-
Get the singletons, which are responsable for everything, much better than keep calling the getter!
ecs::ComponentManager& componentManager = ecs::GetComponentManager(); ecs::EntityManager& entityManager = ecs::GetEntityManager();
-
Create the Entity Manager and the Component Manager, passing a max entity count and a max component per entity count. These 2 values are the limits of the entities and the limits of component per entity
entityManager.Create(100u); componentManager.Create(100u, 32u);
-
Register all the components which are going to be used during the program into the Component Manager, for instance
componentManager.RegisterComponent<Transform>(); componentManager.RegisterComponent<Kinematic>(); componentManager.RegisterComponent<RigidBody>(); componentManager.RegisterComponent<Health>(); componentManager.RegisterComponent<Camera>(); componentManager.RegisterComponent<Render>(); componentManager.RegisterComponent<...>();
-
After this point, create the entity whenever the program needs, for instance
ecs::Entity camera = entityManager.CreateEntity(); ecs::Entity player = entityManager.CreateEntity(); ecs::Entity ... = entityManager.CreateEntity();
-
Handle the different component per entity, adding, removing, updating, collecting, etc, see the next section functions to more details and the example in the examples
-
When everything is finished and the program need to shut down, or simple no longer using some of the component or whataver, remember to remove them, for instance
componentManager.UnregisterComponent<Transform>(); componentManager.UnregisterComponent<Kinematic>(); componentManager.UnregisterComponent<RigidBody>(); componentManager.UnregisterComponent<Health>(); componentManager.UnregisterComponent<Camera>(); componentManager.UnregisterComponent<Render>();
-
At shutdown of the program, destroy the Entity Manager and the Component Manager
componentManager.Destroy(); entityManager.Destroy();
Apart the aformetioned functions to initialise, destroy, register and unregister components, this API has:
componentManager.AddComponent
Is adding a component to an entity, likecomponentManager.AddComponent<Render>(player);
componentManager.RemoveComponent
Is removing a component from an entity, likecomponentManager.RemoveComponent<Render>(player);
componentManager.HasComponents
Return true if an entity as a component, lileconst bool hasRender = componentManager.HasComponents<Render>(player);
componentManager.GetComponent
Return the reference to the component associated to the entity, like:Render& render = componentManager.GetComponent<Render>(player);
componentManager.IterateEntitiesWithAll
Iterate across all entities having all/both the component/s passed as template argument, and returning each entity, like:for (auto iterator : ecs::IterateEntitiesWithAll<Transform, RigidBody, Health>(componentManager)) { // do something with iterator, which is an Entity }
componentManager.IterateEntitiesWithAny
Iterate across all entities having any/either of the component/s passed as template argument, and returning each entity, like:for (auto iterator : ecs::IterateEntitiesWithAny<Transform, RigidBody, Health, Render>(componentManager)) { // do something with iterator, which is an Entity }
componentManager.IterateEntitiesWithNot
Iterate across all entities not having all/both of the component/s passed as template argument, and returning each entity, like:for (auto iterator : ecs::IterateEntitiesWithNot<Health>(componentManager)) { // do something with iterator, which is a Entity }
componentManager.CollectEntitiesWithAll
Collect in a std::vector the entities having all/both the component/s passed as template argument, likestd::vector<ecs::Entity> entitiesCollected; ... ecs::EntityCollector::CollectEntitiesWithAll<Transform, RigidBody, Health>(entitiesCollected); for (const ecs::Entity entityCollected : entitiesCollected) { // do something with entityCollected, the entity collect } entitiesCollected.clear();
componentManager.CollectEntitiesWithAny
Collect in a std::vector the entities having any/either the component/s passed as template argument, likestd::vector<ecs::Entity> entitiesCollected; ... ecs::EntityCollector::CollectEntitiesWithAny<Transform, RigidBody, Health, Render>(entitiesCollected); for (const ecs::Entity entityCollected : entitiesCollected) { // do something with entityCollected, the entity collect } entitiesCollected.clear();
componentManager.CollectEntitiesWithNot
Collect in a std::vector the entities not having all/both the component/s passed as template argument, likestd::vector<ecs::Entity> entitiesCollected; ... ecs::EntityCollector::CollectEntitiesWithNot<Health>(entitiesCollected); for (const ecs::Entity entityCollected : entitiesCollected) { // do something with entityCollected, the entity collect } entitiesCollected.clear();
GPL-3.0
Platform | Build Status |
---|---|
Windows (Visual Studio 2019) |