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