230 lines
5.6 KiB
C++
230 lines
5.6 KiB
C++
/********************\
|
|
| Copyright 2024, |
|
|
| Ulysse Cura |
|
|
\********************/
|
|
|
|
////////////////////////////
|
|
// //
|
|
// Definition de l'ECS. //
|
|
// //
|
|
////////////////////////////
|
|
|
|
#ifndef ECS_HPP
|
|
#define ECS_HPP
|
|
|
|
#include <algorithm>
|
|
#include <array> // array
|
|
#include <bitset> // bitset
|
|
#include <stdexcept> // runtime_error
|
|
#include <memory> // unique_ptr, make_unique
|
|
#include <vector> // vector
|
|
#include "../ChannelManager.hpp" // Class ChannelManager
|
|
|
|
using std::bitset, std::array, std::vector, std::unique_ptr, std::make_unique, std::move, std::forward, std::runtime_error, std::sort, std::remove_if;
|
|
|
|
// Prédefinition des class Component et Entity
|
|
class Component;
|
|
class Entity;
|
|
|
|
// Type pour l'ID des Components
|
|
using ComponentID = std::size_t;
|
|
|
|
// Donne un ID différent en fonction du Component donné
|
|
inline ComponentID getComponentTypeID()
|
|
{
|
|
static ComponentID lastID = 0;
|
|
return lastID++;
|
|
}
|
|
|
|
template<typename T> inline ComponentID getComponentTypeID() noexcept
|
|
{
|
|
static ComponentID typeID = getComponentTypeID();
|
|
return typeID;
|
|
}
|
|
|
|
// Nombre maximum de Components dans une Entity
|
|
constexpr std::size_t maxComponents = 32;
|
|
|
|
// Definition de types pour la contenance des Components
|
|
using ComponentBitSet = bitset<maxComponents>;
|
|
using ComponentArray = array<Component*, maxComponents>;
|
|
|
|
// Definition de la class Components
|
|
struct Component {
|
|
Entity *entity;
|
|
|
|
virtual void init() {}
|
|
virtual void update() {}
|
|
virtual void draw() {}
|
|
|
|
virtual ~Component() {}
|
|
};
|
|
|
|
// Definition de la class Entity
|
|
class Entity {
|
|
public:
|
|
// Met à jours les components
|
|
void update()
|
|
{
|
|
for(auto &c : m_components) c->update();
|
|
}
|
|
|
|
// Dessine les components
|
|
void draw()
|
|
{
|
|
for(auto &c : m_components) c->draw();
|
|
}
|
|
|
|
// Ajouter un composant à l'entité
|
|
bool isActive() const { return m_active; }
|
|
void destroy() { m_active = false; }
|
|
|
|
template <typename T, typename... TArgs>
|
|
T& addComponent(TArgs&&... args)
|
|
{
|
|
if(hasComponent<T>())
|
|
{
|
|
throw runtime_error("Vous ne pouvez pas mettre deux fois le même composant dans la même entité.\n");
|
|
}
|
|
|
|
// Creation d'un pointeur du type donné avec les arguments necessaires
|
|
T *c(new T(forward<TArgs>(args)...));
|
|
// On donne au composant une reference de l'entitée
|
|
c->entity = this;
|
|
|
|
// Création d'un unique_ptr et ajout du composant dans le vecteur et array associé
|
|
unique_ptr<Component> uPtr {c};
|
|
m_components.emplace_back(move(uPtr));
|
|
|
|
m_componentArray[getComponentTypeID<T>()] = c;
|
|
m_componentBitSet[getComponentTypeID<T>()] = true;
|
|
|
|
// Initialisation du composant
|
|
c->init();
|
|
|
|
return *c;
|
|
}
|
|
|
|
// Vérifier si l'entité à un composant donné
|
|
template <typename T>
|
|
bool hasComponent() const
|
|
{
|
|
// Vérifier d'abord si un type exact est présent
|
|
ComponentID id = getComponentTypeID<T>();
|
|
if(m_componentBitSet[id])
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Si non, vérifier dynamiquement tous les composants pour un type dérivé
|
|
for(const auto& c : m_components)
|
|
{
|
|
if (dynamic_cast<T*>(c.get()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Prendre un argument en tant qu'objet
|
|
template <typename T>
|
|
T& getComponent() const
|
|
{
|
|
// Vérification rapide via le BitSet et l'accès direct au composant via l'array
|
|
ComponentID id = getComponentTypeID<T>();
|
|
if (m_componentBitSet[id])
|
|
{
|
|
return *static_cast<T*>(m_componentArray[id]);
|
|
}
|
|
|
|
// Vérification polymorphique avec dynamic_cast
|
|
for (const auto& c : m_components)
|
|
{
|
|
if (T* t = dynamic_cast<T*>(c.get()))
|
|
{
|
|
return *t;
|
|
}
|
|
}
|
|
|
|
throw runtime_error("Composant non trouvé.\n");
|
|
}
|
|
|
|
// Priorité de dessin
|
|
int draw_priority;
|
|
|
|
private:
|
|
bool m_active {true};
|
|
|
|
vector<unique_ptr<Component>> m_components;
|
|
|
|
ComponentArray m_componentArray;
|
|
ComponentBitSet m_componentBitSet;
|
|
};
|
|
|
|
class Manager {
|
|
public:
|
|
void update()
|
|
{
|
|
for(auto &e : m_entities)
|
|
{
|
|
e->update();
|
|
}
|
|
}
|
|
|
|
void draw()
|
|
{
|
|
vector<int> drawOrder(m_entities.size());
|
|
|
|
for(int i {0}; i < static_cast<int>(m_entities.size()); i++) drawOrder[i] = i;
|
|
|
|
sort(drawOrder.begin(), drawOrder.end(),
|
|
[this](const int &a, const int &b)
|
|
{
|
|
return m_entities.at(a)->draw_priority < m_entities.at(b)->draw_priority;
|
|
}
|
|
);
|
|
|
|
for(int i {0}; i < static_cast<int>(m_entities.size()); i++)
|
|
{
|
|
m_entities[drawOrder[i]]->draw();
|
|
}
|
|
}
|
|
|
|
void refresh()
|
|
{
|
|
m_entities.erase(remove_if(m_entities.begin(), m_entities.end(),
|
|
[](const unique_ptr<Entity> &mEntity) {
|
|
return !mEntity->isActive();
|
|
}),
|
|
m_entities.end());
|
|
}
|
|
|
|
Entity &addEntity()
|
|
{
|
|
Entity *e = new Entity();
|
|
unique_ptr<Entity> uPtr{e};
|
|
m_entities.emplace_back(move(uPtr));
|
|
return *e;
|
|
}
|
|
|
|
size_t getNumberOfEntities() const
|
|
{
|
|
return m_entities.size();
|
|
}
|
|
|
|
void destroy(std::size_t index)
|
|
{
|
|
m_entities.at(index).get()->destroy();
|
|
}
|
|
|
|
vector<unique_ptr<Entity>> &getEntities() { return m_entities; }
|
|
ChannelManager &getChannelManager() { return m_channelManager; }
|
|
|
|
private:
|
|
vector<unique_ptr<Entity>> m_entities;
|
|
ChannelManager m_channelManager;
|
|
};
|
|
|
|
#endif
|