✨ simple entity component system.
parent
382cf5d006
commit
095b529129
|
@ -35,6 +35,11 @@ executable(
|
||||||
'src/scenes/Scene.cpp',
|
'src/scenes/Scene.cpp',
|
||||||
'src/scenes/World.cpp',
|
'src/scenes/World.cpp',
|
||||||
|
|
||||||
|
# Entity-Component-System (ECS)
|
||||||
|
'src/ecs/ECS.cpp',
|
||||||
|
'src/ecs/BaseComponent.cpp',
|
||||||
|
'src/ecs/BaseSystem.cpp',
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
'src/logs/Logs.cpp',
|
'src/logs/Logs.cpp',
|
||||||
'src/logs/FileLogs.cpp',
|
'src/logs/FileLogs.cpp',
|
||||||
|
|
|
@ -34,4 +34,7 @@
|
||||||
{} \
|
{} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using entity_t = size_t;
|
||||||
|
using component_t = size_t;
|
||||||
|
|
||||||
#endif
|
#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