2016-03-04 13:59:43 +00:00
|
|
|
|
2016-03-15 10:29:13 +00:00
|
|
|
// This work derives from Vittorio Romeo's code used for cppcon 2015 licensed under the Academic Free License.
|
|
|
|
// His code is available here: https://github.com/SuperV1234/cppcon2015
|
|
|
|
|
|
|
|
|
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>
|
2016-04-20 13:18:25 +00:00
|
|
|
#include <vector>
|
2016-03-05 14:33:24 +00:00
|
|
|
#include <tuple>
|
2016-03-13 09:07:49 +00:00
|
|
|
#include <utility>
|
2016-09-20 11:07:28 +00:00
|
|
|
#include <functional>
|
2016-09-21 12:01:48 +00:00
|
|
|
#include <map>
|
2017-07-13 07:13:37 +00:00
|
|
|
#include <unordered_map>
|
2016-09-21 12:01:48 +00:00
|
|
|
#include <set>
|
|
|
|
#include <unordered_set>
|
2017-07-13 07:13:37 +00:00
|
|
|
#include <algorithm>
|
2016-03-05 14:33:24 +00:00
|
|
|
|
|
|
|
#include "Meta/Combine.hpp"
|
2016-04-20 12:59:47 +00:00
|
|
|
#include "Meta/Matching.hpp"
|
2016-03-05 14:33:24 +00:00
|
|
|
#include "Bitset.hpp"
|
|
|
|
|
2016-03-04 13:59:43 +00:00
|
|
|
namespace EC
|
|
|
|
{
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Manages an EntityComponent system.
|
|
|
|
|
|
|
|
EC::Manager must be created with a list of all used Components and all used tags.
|
|
|
|
|
|
|
|
Note that all components must have a default constructor.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
|
|
|
EC::Manager<TypeList<C0, C1, C2>, TypeList<T0, T1>> manager;
|
|
|
|
\endcode
|
|
|
|
*/
|
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>... >;
|
|
|
|
};
|
2017-07-13 07:13:37 +00:00
|
|
|
using ComponentsStorage =
|
|
|
|
typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
|
2016-03-13 09:07:49 +00:00
|
|
|
// 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-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Initializes the manager with a default capacity.
|
|
|
|
|
|
|
|
The default capacity is set with macro EC_INIT_ENTITIES_SIZE,
|
|
|
|
and will grow by amounts of EC_GROW_SIZE_AMOUNT when needed.
|
|
|
|
*/
|
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) {
|
2017-07-13 07:13:37 +00:00
|
|
|
std::get<std::vector<decltype(t)> >(
|
|
|
|
this->componentsStorage).resize(newCapacity);
|
2016-03-13 09:07:49 +00:00
|
|
|
});
|
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-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Adds an entity to the system, returning the ID of the entity.
|
|
|
|
|
|
|
|
WARNING: The ID of an entity may change after calls to cleanup().
|
|
|
|
Usage of entity IDs should be safe during initialization.
|
2017-07-13 07:13:37 +00:00
|
|
|
Otherwise, only use the ID given during usage of
|
|
|
|
forMatchingSignature().
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
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++;
|
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Marks an entity for deletion.
|
|
|
|
|
|
|
|
A deleted Entity is not actually deleted until cleanup() is called.
|
2017-07-13 07:13:37 +00:00
|
|
|
While an Entity is "deleted" but still in the system, calls to
|
|
|
|
forMatchingSignature() will ignore the Entity.
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
|
|
|
void deleteEntity(const std::size_t& index)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
std::get<bool>(entities.at(index)) = false;
|
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Checks if the Entity with the given ID is in the system.
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
Note that deleted Entities that haven't yet been cleaned up
|
|
|
|
(via cleanup()) are considered still in the system.
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
|
|
|
bool hasEntity(const std::size_t& index) const
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
return index < currentSize;
|
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Checks if the Entity is not marked as deleted.
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
Note that invalid Entities (Entities where calls to hasEntity()
|
|
|
|
returns false) will return false.
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
|
|
|
bool isAlive(const std::size_t& index) const
|
2016-03-14 09:25:38 +00:00
|
|
|
{
|
2016-03-14 11:01:55 +00:00
|
|
|
return hasEntity(index) && std::get<bool>(entities.at(index));
|
2016-03-14 09:25:38 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Returns a const reference to an Entity's info.
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
An Entity's info is a std::tuple with a bool, std::size_t, and a
|
|
|
|
bitset.
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
\n The bool determines if the Entity is alive.
|
|
|
|
\n The std::size_t is the ID to this Entity's data in the system.
|
|
|
|
\n The bitset shows what Components and Tags belong to the Entity.
|
|
|
|
*/
|
|
|
|
const EntitiesTupleType& getEntityInfo(const std::size_t& index) const
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
return entities.at(index);
|
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
2017-07-13 07:13:37 +00:00
|
|
|
\brief Returns a reference to a component belonging to the given
|
|
|
|
Entity.
|
|
|
|
|
|
|
|
This function will return a reference to a Component regardless of
|
|
|
|
whether or not the Entity actually owns the reference. If the Entity
|
|
|
|
doesn't own the Component, changes to the Component will not affect
|
|
|
|
any Entity. It is recommended to use hasComponent() to determine if
|
|
|
|
the Entity actually owns that Component.
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
2016-03-13 09:07:49 +00:00
|
|
|
template <typename Component>
|
2016-09-20 11:31:56 +00:00
|
|
|
Component& getEntityData(const std::size_t& index)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
return std::get<std::vector<Component> >(componentsStorage).at(std::get<std::size_t>(entities.at(index)));
|
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
2017-07-13 07:13:37 +00:00
|
|
|
\brief Returns a reference to a component belonging to the given
|
|
|
|
Entity.
|
2016-09-20 11:31:56 +00:00
|
|
|
|
|
|
|
Note that this function is the same as getEntityData().
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
This function will return a reference to a Component regardless of
|
|
|
|
whether or not the Entity actually owns the reference. If the Entity
|
|
|
|
doesn't own the Component, changes to the Component will not affect
|
|
|
|
any Entity. It is recommended to use hasComponent() to determine if
|
|
|
|
the Entity actually owns that Component.
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
2016-03-14 09:16:09 +00:00
|
|
|
template <typename Component>
|
2016-09-20 11:31:56 +00:00
|
|
|
Component& getEntityComponent(const std::size_t& index)
|
|
|
|
{
|
|
|
|
return getEntityData<Component>(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2017-07-13 07:13:37 +00:00
|
|
|
\brief Checks whether or not the given Entity has the given
|
|
|
|
Component.
|
2016-09-20 11:31:56 +00:00
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
|
|
|
manager.hasComponent<C0>(entityID);
|
|
|
|
\endcode
|
|
|
|
*/
|
|
|
|
template <typename Component>
|
|
|
|
bool hasComponent(const std::size_t& index) const
|
2016-03-14 09:16:09 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
return std::get<BitsetType>(
|
|
|
|
entities.at(index)).template getComponentBit<Component>();
|
2016-03-14 09:16:09 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Checks whether or not the given Entity has the given Tag.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
|
|
|
manager.hasTag<T0>(entityID);
|
|
|
|
\endcode
|
|
|
|
*/
|
2016-03-14 09:16:09 +00:00
|
|
|
template <typename Tag>
|
2016-09-20 11:31:56 +00:00
|
|
|
bool hasTag(const std::size_t& index) const
|
2016-03-14 09:16:09 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
return std::get<BitsetType>(
|
|
|
|
entities.at(index)).template getTagBit<Tag>();
|
2016-03-14 09:16:09 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Does garbage collection on Entities.
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
Does housekeeping on the vector containing Entities that will
|
|
|
|
result in entity IDs changing if some Entities were marked for
|
|
|
|
deletion.
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
<b>This function should be called periodically to correctly handle deletion of entities.</b>
|
|
|
|
*/
|
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]))
|
|
|
|
{
|
|
|
|
if(rhs == 0)
|
|
|
|
{
|
|
|
|
currentSize = 0;
|
|
|
|
return;
|
|
|
|
}
|
2016-08-30 08:34:34 +00:00
|
|
|
std::get<BitsetType>(entities[rhs]).reset();
|
2016-03-14 11:05:49 +00:00
|
|
|
--rhs;
|
2016-03-14 09:16:09 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Adds a component to the given Entity.
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
Additional parameters given to this function will construct the
|
|
|
|
Component with those parameters.
|
2016-09-20 11:31:56 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
Note that if the Entity already has the same component, then it
|
|
|
|
will be overwritten by the newly created Component with the given
|
|
|
|
arguments.
|
2016-09-20 11:31:56 +00:00
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
|
|
|
struct C0
|
|
|
|
{
|
|
|
|
// constructor is compatible as a default constructor
|
|
|
|
C0(int a = 0, char b = 'b') :
|
|
|
|
a(a), b(b)
|
|
|
|
{}
|
|
|
|
|
|
|
|
int a;
|
|
|
|
char b;
|
|
|
|
}
|
|
|
|
|
|
|
|
manager.addComponent<C0>(entityID, 10, 'd');
|
|
|
|
\endcode
|
|
|
|
*/
|
2016-03-13 09:07:49 +00:00
|
|
|
template <typename Component, typename... Args>
|
2016-09-20 11:31:56 +00:00
|
|
|
void addComponent(const std::size_t& entityID, Args&&... args)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
2016-03-14 09:25:38 +00:00
|
|
|
if(!hasEntity(entityID) || !isAlive(entityID))
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-06 10:32:30 +00:00
|
|
|
Component component(std::forward<Args>(args)...);
|
2016-03-13 09:07:49 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
std::get<BitsetType>(
|
|
|
|
entities[entityID]
|
|
|
|
).template getComponentBit<Component>() = true;
|
|
|
|
|
|
|
|
std::get<std::vector<Component> >(
|
|
|
|
componentsStorage
|
|
|
|
)[std::get<std::size_t>(entities[entityID])] = std::move(component);
|
2016-03-13 09:07:49 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Removes the given Component from the given Entity.
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
If the Entity does not have the Component given, nothing will
|
|
|
|
change.
|
2016-09-20 11:31:56 +00:00
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
|
|
|
manager.removeComponent<C0>(entityID);
|
|
|
|
\endcode
|
|
|
|
*/
|
2016-03-13 09:07:49 +00:00
|
|
|
template <typename Component>
|
2016-09-20 11:31:56 +00:00
|
|
|
void removeComponent(const std::size_t& entityID)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
2016-03-14 09:25:38 +00:00
|
|
|
if(!hasEntity(entityID) || !isAlive(entityID))
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
std::get<BitsetType>(
|
|
|
|
entities[entityID]
|
|
|
|
).template getComponentBit<Component>() = false;
|
2016-03-13 09:07:49 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Adds the given Tag to the given Entity.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
|
|
|
manager.addTag<T0>(entityID);
|
|
|
|
\endcode
|
|
|
|
*/
|
2016-03-13 09:07:49 +00:00
|
|
|
template <typename Tag>
|
2016-09-20 11:31:56 +00:00
|
|
|
void addTag(const std::size_t& entityID)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
2016-03-14 09:25:38 +00:00
|
|
|
if(!hasEntity(entityID) || !isAlive(entityID))
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
std::get<BitsetType>(
|
|
|
|
entities[entityID]
|
|
|
|
).template getTagBit<Tag>() = true;
|
2016-03-13 09:07:49 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Removes the given Tag from the given Entity.
|
|
|
|
|
|
|
|
If the Entity does not have the Tag given, nothing will change.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
|
|
|
manager.removeTag<T0>(entityID);
|
|
|
|
\endcode
|
|
|
|
*/
|
2016-03-13 09:07:49 +00:00
|
|
|
template <typename Tag>
|
2016-09-20 11:31:56 +00:00
|
|
|
void removeTag(const std::size_t& entityID)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
2016-03-14 09:25:38 +00:00
|
|
|
if(!hasEntity(entityID) || !isAlive(entityID))
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
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>
|
2017-07-13 07:13:37 +00:00
|
|
|
static void call(
|
|
|
|
const std::size_t& entityID,
|
|
|
|
CType& ctype,
|
|
|
|
Function&& function)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
function(
|
|
|
|
entityID,
|
|
|
|
ctype.template getEntityData<Types>(entityID)...
|
|
|
|
);
|
|
|
|
}
|
2016-09-20 11:07:28 +00:00
|
|
|
|
|
|
|
template <typename CType, typename Function>
|
2017-07-13 07:13:37 +00:00
|
|
|
void callInstance(
|
|
|
|
const std::size_t& entityID,
|
|
|
|
CType& ctype,
|
|
|
|
Function&& function) const
|
2016-09-20 11:07:28 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
ForMatchingSignatureHelper<Types...>::call(
|
|
|
|
entityID,
|
|
|
|
ctype,
|
|
|
|
std::forward<Function>(function));
|
2016-09-20 11:07:28 +00:00
|
|
|
}
|
2016-03-13 09:07:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
2017-07-13 07:13:37 +00:00
|
|
|
\brief Calls the given function on all Entities matching the given
|
|
|
|
Signature.
|
2016-09-20 11:31:56 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
The function object given to this function must accept std::size_t
|
|
|
|
as its first parameter and Component references for the rest of the
|
|
|
|
parameters. Tags specified in the Signature are only used as
|
|
|
|
filters and will not be given as a parameter to the function.
|
2016-09-20 11:31:56 +00:00
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
2017-07-13 07:13:37 +00:00
|
|
|
manager.forMatchingSignature<TypeList<C0, C1, T0>>([] (
|
|
|
|
std::size_t ID, C0& component0, C1& component1) {
|
2016-09-20 11:31:56 +00:00
|
|
|
// Lambda function contents here
|
|
|
|
});
|
|
|
|
\endcode
|
2017-07-13 07:13:37 +00:00
|
|
|
Note, the ID given to the function is not permanent. An entity's ID
|
|
|
|
may change when cleanup() is called.
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
2016-03-13 09:07:49 +00:00
|
|
|
template <typename Signature, typename Function>
|
|
|
|
void forMatchingSignature(Function&& function)
|
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
using SignatureComponents =
|
|
|
|
typename EC::Meta::Matching<Signature, ComponentsList>::type;
|
|
|
|
using Helper =
|
|
|
|
EC::Meta::Morph<
|
|
|
|
SignatureComponents,
|
|
|
|
ForMatchingSignatureHelper<> >;
|
|
|
|
|
|
|
|
BitsetType signatureBitset =
|
|
|
|
BitsetType::template generateBitset<Signature>();
|
2016-03-13 09:07:49 +00:00
|
|
|
for(std::size_t i = 0; i < currentSize; ++i)
|
|
|
|
{
|
|
|
|
if(!std::get<bool>(entities[i]))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
if((signatureBitset & std::get<BitsetType>(entities[i]))
|
|
|
|
== signatureBitset)
|
2016-03-13 09:07:49 +00:00
|
|
|
{
|
|
|
|
Helper::call(i, *this, std::forward<Function>(function));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-04 13:59:43 +00:00
|
|
|
|
2016-09-20 11:07:28 +00:00
|
|
|
private:
|
2017-07-13 07:13:37 +00:00
|
|
|
std::unordered_map<std::size_t, std::function<void()> > forMatchingFunctions;
|
|
|
|
std::size_t functionIndex = 0;
|
2016-09-20 11:07:28 +00:00
|
|
|
|
|
|
|
public:
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Stores a function in the manager to be called later.
|
|
|
|
|
|
|
|
As an alternative to calling functions directly with
|
|
|
|
forMatchingSignature(), functions can be stored in the manager to
|
2017-07-12 13:02:02 +00:00
|
|
|
be called later with callForMatchingFunctions() and
|
2017-07-13 07:13:37 +00:00
|
|
|
callForMatchingFunction, and removed with
|
|
|
|
clearForMatchingFunctions() and removeForMatchingFunction().
|
2016-09-20 11:31:56 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
The syntax for the Function is the same as with
|
|
|
|
forMatchingSignature().
|
2016-09-20 11:31:56 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
Note that functions will be called in the same order they are
|
|
|
|
inserted if called by callForMatchingFunctions() unless the
|
|
|
|
internal functionIndex counter has wrapped around (is a
|
|
|
|
std::size_t). Calling clearForMatchingFunctions() will reset this
|
|
|
|
counter to zero.
|
2016-09-21 12:01:48 +00:00
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
2017-07-13 07:13:37 +00:00
|
|
|
manager.addForMatchingFunction<TypeList<C0, C1, T0>>([] (
|
|
|
|
std::size_t ID, C0& component0, C1& component1) {
|
2016-09-20 11:31:56 +00:00
|
|
|
// Lambda function contents here
|
|
|
|
});
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
// call all stored functions
|
|
|
|
manager.callForMatchingFunctions();
|
2016-09-20 11:31:56 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
// remove all stored functions
|
|
|
|
manager.clearForMatchingFunctions();
|
2016-09-20 11:31:56 +00:00
|
|
|
\endcode
|
2016-09-21 12:01:48 +00:00
|
|
|
|
|
|
|
\return The index of the function, used for deletion with
|
|
|
|
deleteForMatchingFunction() or filtering with
|
2017-07-13 07:13:37 +00:00
|
|
|
keepSomeMatchingFunctions() or removeSomeMatchingFunctions(),
|
|
|
|
or calling with callForMatchingFunction().
|
2016-09-20 11:31:56 +00:00
|
|
|
*/
|
2016-09-20 11:07:28 +00:00
|
|
|
template <typename Signature, typename Function>
|
2017-07-13 07:13:37 +00:00
|
|
|
std::size_t addForMatchingFunction(Function&& function)
|
2016-09-20 11:07:28 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
while(forMatchingFunctions.find(functionIndex)
|
|
|
|
!= forMatchingFunctions.end())
|
|
|
|
{
|
|
|
|
++functionIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
using SignatureComponents =
|
|
|
|
typename EC::Meta::Matching<Signature, ComponentsList>::type;
|
|
|
|
using Helper =
|
|
|
|
EC::Meta::Morph<
|
|
|
|
SignatureComponents,
|
|
|
|
ForMatchingSignatureHelper<> >;
|
2016-09-20 11:07:28 +00:00
|
|
|
|
|
|
|
Helper helper;
|
2017-07-13 07:13:37 +00:00
|
|
|
BitsetType signatureBitset =
|
|
|
|
BitsetType::template generateBitset<Signature>();
|
2016-09-20 11:07:28 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
forMatchingFunctions.emplace(std::make_pair(
|
|
|
|
functionIndex,
|
|
|
|
[function, signatureBitset, helper, this] ()
|
|
|
|
{
|
2016-09-20 11:07:28 +00:00
|
|
|
for(std::size_t i = 0; i < this->currentSize; ++i)
|
|
|
|
{
|
|
|
|
if(!std::get<bool>(this->entities[i]))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-13 07:13:37 +00:00
|
|
|
if((signatureBitset
|
|
|
|
& std::get<BitsetType>(this->entities[i]))
|
|
|
|
== signatureBitset)
|
2016-09-20 11:07:28 +00:00
|
|
|
{
|
|
|
|
helper.callInstance(i, *this, function);
|
|
|
|
}
|
|
|
|
}
|
2016-09-21 12:01:48 +00:00
|
|
|
}));
|
|
|
|
|
|
|
|
return functionIndex++;
|
2016-09-20 11:07:28 +00:00
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Call all stored functions.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
2017-07-13 07:13:37 +00:00
|
|
|
manager.addForMatchingFunction<TypeList<C0, C1, T0>>([] (
|
|
|
|
std::size_t ID, C0& component0, C1& component1) {
|
2016-09-20 11:31:56 +00:00
|
|
|
// Lambda function contents here
|
|
|
|
});
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
// call all stored functions
|
|
|
|
manager.callForMatchingFunctions();
|
2016-09-20 11:31:56 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
// remove all stored functions
|
|
|
|
manager.clearForMatchingFunctions();
|
2016-09-20 11:31:56 +00:00
|
|
|
\endcode
|
|
|
|
*/
|
2016-09-20 11:07:28 +00:00
|
|
|
void callForMatchingFunctions()
|
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
for(auto functionIter = forMatchingFunctions.begin();
|
|
|
|
functionIter != forMatchingFunctions.end();
|
|
|
|
++functionIter)
|
2016-09-20 11:07:28 +00:00
|
|
|
{
|
2016-09-21 12:01:48 +00:00
|
|
|
functionIter->second();
|
2016-09-20 11:07:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-12 13:02:02 +00:00
|
|
|
/*!
|
|
|
|
\brief Call a specific stored function.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
2017-07-13 07:13:37 +00:00
|
|
|
std::size_t id =
|
|
|
|
manager.addForMatchingFunction<TypeList<C0, C1, T0>>(
|
2017-07-12 13:02:02 +00:00
|
|
|
[] (std::size_t ID, C0& c0, C1& c1) {
|
|
|
|
// Lambda function contents here
|
|
|
|
});
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
// call the previously added function
|
|
|
|
manager.callForMatchingFunction(id);
|
2017-07-12 13:02:02 +00:00
|
|
|
\endcode
|
|
|
|
|
|
|
|
\return False if a function with the given id does not exist.
|
|
|
|
*/
|
2017-07-13 07:13:37 +00:00
|
|
|
bool callForMatchingFunction(std::size_t id)
|
2017-07-12 13:02:02 +00:00
|
|
|
{
|
|
|
|
auto iter = forMatchingFunctions.find(id);
|
|
|
|
if(iter == forMatchingFunctions.end())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
iter->second();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
/*!
|
|
|
|
\brief Remove all stored functions.
|
|
|
|
|
2016-09-21 12:01:48 +00:00
|
|
|
Also resets the index counter of stored functions to 0.
|
|
|
|
|
2016-09-20 11:31:56 +00:00
|
|
|
Example:
|
|
|
|
\code{.cpp}
|
2017-07-13 07:13:37 +00:00
|
|
|
manager.addForMatchingFunction<TypeList<C0, C1, T0>>([] (
|
|
|
|
std::size_t ID, C0& component0, C1& component1) {
|
2016-09-20 11:31:56 +00:00
|
|
|
// Lambda function contents here
|
|
|
|
});
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
// call all stored functions
|
|
|
|
manager.callForMatchingFunctions();
|
2016-09-20 11:31:56 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
// remove all stored functions
|
|
|
|
manager.clearForMatchingFunctions();
|
2016-09-20 11:31:56 +00:00
|
|
|
\endcode
|
|
|
|
*/
|
2016-09-20 11:07:28 +00:00
|
|
|
void clearForMatchingFunctions()
|
|
|
|
{
|
|
|
|
forMatchingFunctions.clear();
|
2016-09-21 12:01:48 +00:00
|
|
|
functionIndex = 0;
|
|
|
|
}
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
/*!
|
|
|
|
\brief Removes a function that has the given id.
|
|
|
|
|
|
|
|
\return True if a function was erased.
|
|
|
|
*/
|
|
|
|
bool removeForMatchingFunction(std::size_t id)
|
|
|
|
{
|
|
|
|
return forMatchingFunctions.erase(id) == 1;
|
|
|
|
}
|
|
|
|
|
2016-09-21 12:01:48 +00:00
|
|
|
/*!
|
|
|
|
\brief Removes all functions that do not have the index specified
|
|
|
|
in argument "list".
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
The given List must be iterable.
|
|
|
|
This is the only requirement, so a set could also be given.
|
|
|
|
|
|
|
|
\return The number of functions deleted.
|
2016-09-21 12:01:48 +00:00
|
|
|
*/
|
|
|
|
template <typename List>
|
2017-07-13 07:13:37 +00:00
|
|
|
std::size_t keepSomeMatchingFunctions(List list)
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
std::size_t deletedCount = 0;
|
2017-07-13 08:28:45 +00:00
|
|
|
for(auto iter = forMatchingFunctions.begin(); iter != forMatchingFunctions.end();)
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 08:28:45 +00:00
|
|
|
if(std::find(list.begin(), list.end(), iter->first) == list.end())
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 08:28:45 +00:00
|
|
|
iter = forMatchingFunctions.erase(iter);
|
|
|
|
++deletedCount;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++iter;
|
2016-09-21 12:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-13 07:13:37 +00:00
|
|
|
|
|
|
|
return deletedCount;
|
2016-09-21 12:01:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Removes all functions that do not have the index specified
|
|
|
|
in argument "list".
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
This function allows for passing an initializer list.
|
|
|
|
|
|
|
|
\return The number of functions deleted.
|
2016-09-21 12:01:48 +00:00
|
|
|
*/
|
2017-07-13 07:13:37 +00:00
|
|
|
std::size_t keepSomeMatchingFunctions(
|
|
|
|
std::initializer_list<std::size_t> list)
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
return keepSomeMatchingFunctions<decltype(list)>(list);
|
2016-09-21 12:01:48 +00:00
|
|
|
}
|
|
|
|
|
2017-07-12 13:02:02 +00:00
|
|
|
/*!
|
2017-07-13 07:13:37 +00:00
|
|
|
\brief Removes all functions that do have the index specified
|
|
|
|
in argument "list".
|
2017-07-12 13:02:02 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
The given List must be iterable.
|
|
|
|
This is the only requirement, so a set could also be given.
|
2017-07-12 13:02:02 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
\return The number of functions deleted.
|
|
|
|
*/
|
|
|
|
template <typename List>
|
|
|
|
std::size_t removeSomeMatchingFunctions(List list)
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
std::size_t deletedCount = 0;
|
|
|
|
for(auto listIter = list.begin();
|
|
|
|
listIter != list.end();
|
|
|
|
++listIter)
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
deletedCount += forMatchingFunctions.erase(*listIter);
|
2016-09-21 12:01:48 +00:00
|
|
|
}
|
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
return deletedCount;
|
2016-09-21 12:01:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2017-07-13 07:13:37 +00:00
|
|
|
\brief Removes all functions that do have the index specified
|
|
|
|
in argument "list".
|
|
|
|
|
|
|
|
This function allows for passing an initializer list.
|
2016-09-21 12:01:48 +00:00
|
|
|
|
2017-07-13 07:13:37 +00:00
|
|
|
\return The number of functions deleted.
|
2016-09-21 12:01:48 +00:00
|
|
|
*/
|
2017-07-13 07:13:37 +00:00
|
|
|
std::size_t removeSomeMatchingFunctions(
|
|
|
|
std::initializer_list<std::size_t> list)
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
return removeSomeMatchingFunctions<decltype(list)>(list);
|
2016-09-21 12:01:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Deletes the specified function.
|
|
|
|
|
|
|
|
The index of a function is returned from addForMatchingFunction()
|
|
|
|
so there is no other way to get the index of a function.
|
2017-07-13 07:13:37 +00:00
|
|
|
|
|
|
|
\return True if function existed and has been deleted.
|
2016-09-21 12:01:48 +00:00
|
|
|
*/
|
2017-07-13 07:13:37 +00:00
|
|
|
bool deleteForMatchingFunction(std::size_t index)
|
2016-09-21 12:01:48 +00:00
|
|
|
{
|
2017-07-13 07:13:37 +00:00
|
|
|
return forMatchingFunctions.erase(index) == 1;
|
2016-09-20 11:07:28 +00:00
|
|
|
}
|
|
|
|
|
2016-09-21 12:01:48 +00:00
|
|
|
/*!
|
|
|
|
\brief Resets the Manager, removing all entities.
|
|
|
|
|
|
|
|
Some data may persist but will be overwritten when new entities
|
|
|
|
are added. Thus, do not depend on data to persist after a call to
|
|
|
|
reset().
|
|
|
|
*/
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
clearForMatchingFunctions();
|
|
|
|
|
|
|
|
currentSize = 0;
|
|
|
|
currentCapacity = 0;
|
|
|
|
resize(EC_INIT_ENTITIES_SIZE);
|
|
|
|
}
|
2016-03-04 13:59:43 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|