#ifndef EC_MANAGER_HPP #define EC_MANAGER_HPP #define EC_INIT_ENTITIES_SIZE 256 #define EC_GROW_SIZE_AMOUNT 256 #include #include #include #include "Meta/Combine.hpp" #include "Bitset.hpp" namespace EC { template struct Manager { public: using Combined = EC::Meta::Combine; using BitsetType = EC::Bitset; private: template struct Storage { using type = std::tuple... >; }; using ComponentsStorage = typename EC::Meta::Morph >::type; // Entity: isAlive, dataIndex, ComponentsTags Info using EntitiesTupleType = std::tuple; using EntitiesType = std::vector; EntitiesType entities; ComponentsStorage componentsStorage; std::size_t currentCapacity = 0; std::size_t currentSize = 0; public: Manager() { resize(EC_INIT_ENTITIES_SIZE); } private: void resize(std::size_t newCapacity) { if(currentCapacity >= newCapacity) { return; } EC::Meta::forEach([this, newCapacity] (auto t) { std::get >(this->componentsStorage).resize(newCapacity); }); entities.resize(newCapacity); for(std::size_t i = currentCapacity; i < newCapacity; ++i) { entities[i] = std::make_tuple(false, i, BitsetType{}); } currentCapacity = newCapacity; } public: std::size_t addEntity() { if(currentSize == currentCapacity) { resize(currentCapacity + EC_GROW_SIZE_AMOUNT); } std::get(entities[currentSize]) = true; return currentSize++; } void deleteEntity(std::size_t index) { std::get(entities.at(index)) = false; } bool hasEntity(std::size_t index) const { return index < currentSize; } bool isAlive(std::size_t index) const { return std::get(entities.at(index)); } const EntitiesTupleType& getEntityInfo(std::size_t index) const { return entities.at(index); } template Component& getEntityData(std::size_t index) { return std::get >(componentsStorage).at(std::get(entities.at(index))); } template bool hasComponent(std::size_t index) const { return std::get(entities.at(index)).template getComponentBit(); } template bool hasTag(std::size_t index) const { return std::get(entities.at(index)).template getTagBit(); } void cleanup() { if(currentSize == 0) { return; } std::size_t rhs = currentSize - 1; std::size_t lhs = 0; while(lhs < rhs) { while(!std::get(entities[rhs])) { --rhs; if(rhs == 0) { currentSize = 0; return; } } if(lhs >= rhs) { break; } else if(!std::get(entities[lhs])) { // lhs is marked for deletion // swap lhs entity with rhs entity std::swap(entities[lhs], entities.at(rhs)); // clear deleted bitset std::get(entities[rhs]).reset(); // inc/dec pointers ++lhs; --rhs; } else { ++lhs; } } currentSize = rhs + 1; } template void addComponent(std::size_t entityID, Args&&... args) { if(!hasEntity(entityID) || !isAlive(entityID)) { return; } Component component(args...); std::get(entities[entityID]).template getComponentBit() = true; std::get >(componentsStorage)[std::get(entities[entityID])] = component; } template void removeComponent(std::size_t entityID) { if(!hasEntity(entityID) || !isAlive(entityID)) { return; } std::get(entities[entityID]).template getComponentBit() = false; } template void addTag(std::size_t entityID) { if(!hasEntity(entityID) || !isAlive(entityID)) { return; } std::get(entities[entityID]).template getTagBit() = true; } template void removeTag(std::size_t entityID) { if(!hasEntity(entityID) || !isAlive(entityID)) { return; } std::get(entities[entityID]).template getTagBit() = false; } private: template struct ForMatchingSignatureHelper { template static void call(std::size_t entityID, CType& ctype, Function&& function) { function( entityID, ctype.template getEntityData(entityID)... ); } }; public: template void forMatchingSignature(Function&& function) { using SignatureComponents = typename EC::Meta::Matching::type; using Helper = EC::Meta::Morph >; BitsetType signatureBitset = BitsetType::template generateBitset(); for(std::size_t i = 0; i < currentSize; ++i) { if(!std::get(entities[i])) { continue; } if((signatureBitset & std::get(entities[i])) == signatureBitset) { Helper::call(i, *this, std::forward(function)); } } } }; } #endif