#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; } 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))); } void cleanup() { std::size_t rhs = currentSize - 1; std::size_t lhs = 0; while(lhs < rhs) { if(!std::get(entities[lhs])) { // lhs is marked for deletion // swap lhs entity with rhs entity std::swap(entities[lhs], entities[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)) { 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)) { return; } std::get(entities[entityID]).template getComponentBit() = false; } template void addTag(std::size_t entityID) { if(!hasEntity(entityID)) { return; } std::get(entities[entityID]).template getTagBit() = true; } template void removeTag(std::size_t entityID) { if(!hasEntity(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