✨ simple entity component system.
parent
382cf5d006
commit
095b529129
|
@ -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',
|
||||
|
|
|
@ -34,4 +34,7 @@
|
|||
{} \
|
||||
}
|
||||
|
||||
using entity_t = size_t;
|
||||
using component_t = size_t;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#include "BaseComponent.hpp"
|
||||
|
||||
namespace ml
|
||||
{
|
||||
/*virtual*/ BaseComponent::~BaseComponent()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
#include "BaseSystem.hpp"
|
||||
|
||||
namespace ml
|
||||
{
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
Reference in New Issue