#ifndef ECS_HPP #define ECS_HPP 1 #include "entitycomponents.hpp" #include "util.hpp" #include #include #include #include #include #include #include namespace ecs { struct ComponentContainer { std::vector packed{}; std::vector sparse{}; std::queue free{}; void resize(size_t n) { sparse.resize(n, -1); } template void insert(unsigned id, const T &c) { assert(sparse.size() > id); if(free.empty()) { sparse[id] = (int)packed.size(); packed.push_back(c); }else { sparse[id] = (int)free.front(); packed[sparse[id]] = c; free.pop(); } } void remove(unsigned id) { assert(sparse.size() > id); if(sparse[id] > -1) { free.push((unsigned)sparse[id]); } sparse[id] = -1; } template T &reduce(unsigned id) { assert(sparse.size() > id); assert(sparse[id] > -1); return std::get(packed[sparse[id]]); } }; class EntityMan; struct Entity { EntityMan *man; component_sig sig{}; unsigned id; Entity(const Entity &e) = default; Entity(EntityMan *Man, unsigned Id) : man(Man), sig(0), id(Id) {} template constexpr bool contains() { return sig.test(get_index()); } template T &get(); template Entity &addComponent(const T &component); }; class EntityMan { std::array> m_components; std::vector m_entities; std::queue m_free; public: Entity &operator[](std::size_t i) { return m_entities[i]; } Entity newEntity() { std::size_t newid = 0; if(!m_free.empty()) { newid = m_free.front(); m_free.pop(); }else{ newid = m_entities.size(); m_entities.emplace_back(this, newid); for(auto &container : m_components) container.resize(m_entities.size()); } return m_entities[newid]; } void deleteEntity(Entity &e) { for(auto &container : m_components) container.remove(e.id); e.sig.reset(); m_free.push(e.id); } template T &get(const Entity &e) { constexpr unsigned cid = get_index(); return m_components[cid].reduce(e.id); } template auto getWith() { constexpr unsigned cid = get_index(); auto e_hc = [](Entity const e) { return e.sig[cid]; }; return std::ranges::views::filter(m_entities, e_hc); } std::span all() { return std::span(m_entities.begin(), m_entities.end()); } std::size_t size() { return m_entities.size(); } template Entity &addComponent(Entity &entity, const T& component) { constexpr unsigned cid = get_index(); m_components[cid].insert(entity.id, component); m_entities[entity.id].sig[cid] = 1; return entity; } }; template T &Entity::get() { return man->get(*this); } template Entity &Entity::addComponent(const T& component) { return man->addComponent(*this, component); } } #endif