simple entity component system.

main
bog 2023-10-27 19:33:20 +02:00
parent 382cf5d006
commit 095b529129
8 changed files with 221 additions and 0 deletions

View File

@ -35,6 +35,11 @@ executable(
'src/scenes/Scene.cpp',
'src/scenes/World.cpp',
# Entity-Component-System (ECS)
'src/ecs/ECS.cpp',
'src/ecs/BaseComponent.cpp',
'src/ecs/BaseSystem.cpp',
# Logs
'src/logs/Logs.cpp',
'src/logs/FileLogs.cpp',

View File

@ -34,4 +34,7 @@
{} \
}
using entity_t = size_t;
using component_t = size_t;
#endif

View File

@ -0,0 +1,8 @@
#include "BaseComponent.hpp"
namespace ml
{
/*virtual*/ BaseComponent::~BaseComponent()
{
}
}

18
src/ecs/BaseComponent.hpp Normal file
View File

@ -0,0 +1,18 @@
#ifndef ml_BASECOMPONENT_HPP
#define ml_BASECOMPONENT_HPP
#include "../commons.hpp"
namespace ml
{
class BaseComponent
{
public:
BaseComponent() = default;
virtual ~BaseComponent();
private:
};
}
#endif

5
src/ecs/BaseSystem.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "BaseSystem.hpp"
namespace ml
{
}

42
src/ecs/BaseSystem.hpp Normal file
View File

@ -0,0 +1,42 @@
#ifndef ml_BASESYSTEM_HPP
#define ml_BASESYSTEM_HPP
#include "ECS.hpp"
#include "../commons.hpp"
namespace ml
{
template <typename... Args>
class BaseSystem
{
public:
explicit BaseSystem(ECS& ecs)
: m_ecs { ecs }
, m_sig { m_ecs.signature<Args...>() }
{
}
virtual ~BaseSystem() = default;
virtual void update(std::vector<entity_t> entities)
{
for (auto entity: entities)
{
signature_t entity_sig = m_ecs.signature(entity);
if ((entity_sig & m_sig) == m_sig)
{
process(entity);
}
}
}
virtual void process(entity_t entity) = 0;
protected:
ECS& m_ecs;
signature_t m_sig;
};
}
#endif

27
src/ecs/ECS.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "ECS.hpp"
namespace ml
{
/*explicit*/ ECS::ECS()
{
}
/*virtual*/ ECS::~ECS()
{
}
signature_t ECS::signature(entity_t entity) const
{
int res = 0;
for (component_t comp_id=0; comp_id < MAX_COMPONENTS; comp_id++)
{
if (m_entities[entity][comp_id] != nullptr)
{
res = res | (1 << comp_id);
}
}
return res;
}
}

113
src/ecs/ECS.hpp Normal file
View File

@ -0,0 +1,113 @@
#ifndef ml_ECS_HPP
#define ml_ECS_HPP
#include "../commons.hpp"
#include "BaseComponent.hpp"
namespace ml
{
using components_t = std::unordered_map<component_t,
std::unique_ptr<BaseComponent>>;
using signature_t = size_t;
constexpr size_t MAX_ENTITIES = 4096;
constexpr size_t MAX_COMPONENTS = 128;
ML_ERROR(ecs_error);
class ECS
{
public:
explicit ECS();
virtual ~ECS();
template <typename T, typename... Args>
signature_t signature();
signature_t signature(entity_t entity) const;
template <typename T>
size_t component_id();
template <typename T, typename... Args>
entity_t spawn(T component);
template <typename T, typename... Args>
entity_t spawn(T component, Args... args);
template <typename T>
T& get(entity_t entity);
private:
std::array<std::array<std::unique_ptr<BaseComponent>,
MAX_COMPONENTS>, MAX_ENTITIES>
m_entities;
size_t m_entities_count = 0;
size_t m_component_counter = 1;
};
template <typename T, typename... Args>
signature_t ECS::signature()
{
component_t id = component_id<T>();
size_t sig = 1 << id;
if constexpr (sizeof...(Args) != 0)
{
sig |= signature<Args...>();
}
return sig;
}
template <typename T>
size_t ECS::component_id()
{
static size_t comp_id = m_component_counter++;
return comp_id;
}
template <typename T, typename... Args>
entity_t ECS::spawn(T component)
{
size_t comp_id = component_id<T>();
m_entities[m_entities_count][comp_id] =
std::make_unique<T>(component);
m_entities_count++;
return m_entities_count - 1;
}
template <typename T, typename... Args>
entity_t ECS::spawn(T component, Args... args)
{
size_t comp_id = component_id<T>();
entity_t entity = spawn(args...);
m_entities[entity][comp_id] =
std::make_unique<T>(component);
return entity;
}
template <typename T>
T& ECS::get(entity_t entity)
{
size_t comp_id = component_id<T>();
auto* comp = m_entities[entity][comp_id].get();
if (comp == nullptr)
{
throw ecs_error {"component not found in entity '"
+ std::to_string(entity)
+ "'"};
}
return static_cast<T&>(*comp);
}
}
#endif