An Implementation of Entity Component Systems Pattern leveraging Sparse Sets and Bit Fields for Efficiency and Performance.
- A Simple Entity System and API, where Entities are just integers.
- Smart and Fast Iterations by Storing Matching Entities in a Sparse set.
- Safety Measures to avoid adding Duplicate Components to Entities, removing non-existent Components from Entities or destroying Dead entities.
- Automatic de-allocation of Component Resources on Entity Deletion. This means, No need to worry about Components once added.
- Filtering allows Inclusion and Exclusion of specific Components, on a Per-System Basis.
- Components are stored in contiguous Memory for Cache Efficiency.
Include the Single Header AtlasECS.hpp
in your Project. Following is an Example of how to use the Library:
//Include this File
#include "include/AtlasECS.hpp"
#include "TestComponents.h"
#include "TestSystem.h"
#include <iostream>
int main()
{
// Create an ECS World/Context. There can be Multiple Worlds for Physics,
// Rendering, Networking and So on.
// The Parameter takes the Initial Number of Entities to reserve Memory.
// Choose a Large Number to avoid Memory Moving Around.
std::shared_ptr<atlas::CWorld> world = std::make_shared<atlas::CWorld>(1000);
// Systems derive from CSystem and can selectively access
// for a Combination of Components.
CTestSystem testSystem(world);
// Entities can be Created using the CreateEntity Function
// Entity IDs can repeat across Worlds, but is unique within a World.
Entity e1 = world->CreateEntity();
// Components can be Added to an Entity using the Following Syntax.
world->AddComponent<FNameComponent>(e2, std::move(FNameComponent("Entity 1")));
// Multiple Components can be added with the Same AddComponent Call
world->AddComponent<FPositionComponent, FRotationComponent>(e2, FPositionComponent(0,0,0), FRotationComponent(30,85,90));
// Or Entities can be Created with Components, as Shown Below
Entity e2 = world->CreateEntity<FNameComponent, FPositionComponent, FRotationComponent>
(FNameComponent("Entity 2"),FPositionComponent(1,1,1), FRotationComponent(0,0,0));
// A Component can be Removed using the `RemoveComponent` Function
world->RemoveComponent<FPositionComponent>(e2);
// Destroying an Entity would destroy all the Components associated with it.
world->DestroyEntity(e2);
// Query whether the Entity is alive.
world->IsEntityAlive(e2);
// Get Components of type would return an Array of the Components of the Passed Type
// and the Number of **Valid** Components in the Array.
auto[array, count] = world->GetComponentsOfType<FNameComponent>();
return 0;
}
And, here is how to setup a System:
#include "AtlasECS.hpp"
class CTestSystem : public atlas::CSystem
{
public:
CTestSystem(std::shared_ptr<atlas::CWorld> world)
:CSystem(world)
{
// Entities are automatically added and removed from this
// System's Group, as Components are added/removed
// and upon entity Destruction.
// Only consider Elements with the Following Components
this->MatchEntitiesWith<FPositionComponent, FRotationComponent>();
// Discard Entities with atleast one of these Components,
// even if they have matching Components.
this->ExcludeEntitiesWithAnyOf<FStaticMeshComponent, FTurretComponent>();
// Discard Entities with all of these Components,
// even if they have matching Components.
this->ExcludeEntitiesWithAllOf<FHealthComponent, FNavmeshComponent>();
}
void OnUpdate(float dt)
{
// GetComponentsOfType returns a Tuple of [T*, count]
auto[position_array, pcount] = world->GetComponentsOfType<FPositionComponent>();
auto[rotation_array, rcount] = world->GetComponentsOfType<FRotationComponent>();
// All the Matching Entities can be Accessed from
// the m_MatchingEntities Member of the System
for(auto itr = m_MatchingEntities.begin(); itr != m_MatchingEntities.end(); ++itr)
{
Entity e = *itr;
position_array[e] += vec3(1.0,5.0,10.0) * dt;
rotation_array[e] += vec3(0.5f, 1.0f, 0.6f) * dt;
}
}
};