Sdk/EntityList: Automatically remove entities from lists on destruction

This commit is contained in:
Lynix 2017-05-14 22:13:31 +02:00
parent 3d25501f9f
commit bb3eebb9cc
6 changed files with 81 additions and 22 deletions

View File

@ -17,14 +17,17 @@
namespace Ndk
{
class BaseComponent;
class BaseSystem;
class Entity;
class EntityList;
class World;
using EntityHandle = Nz::ObjectHandle<Entity>;
class NDK_API Entity : public Nz::HandledObject<Entity>
{
friend class BaseSystem;
friend BaseSystem;
friend EntityList;
friend World;
public:
@ -78,13 +81,16 @@ namespace Ndk
inline Nz::Bitset<>& GetRemovedComponentBits();
inline void RegisterEntityList(EntityList* list);
inline void RegisterSystem(SystemIndex index);
inline void SetWorld(World* world) noexcept;
inline void UnregisterEntityList(EntityList* list);
inline void UnregisterSystem(SystemIndex index);
std::vector<std::unique_ptr<BaseComponent>> m_components;
std::vector<EntityList*> m_containedInLists;
Nz::Bitset<> m_componentBits;
Nz::Bitset<> m_removedComponentBits;
Nz::Bitset<> m_systemBits;

View File

@ -6,6 +6,7 @@
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <algorithm>
#include <cassert>
#include <type_traits>
#include <utility>
@ -257,11 +258,10 @@ namespace Ndk
return m_removedComponentBits;
}
/*!
* \brief Registers a system for the entity
*
* \param index Index of the system
*/
inline void Entity::RegisterEntityList(EntityList* list)
{
m_containedInLists.push_back(list);
}
inline void Entity::RegisterSystem(SystemIndex index)
{
@ -289,6 +289,16 @@ namespace Ndk
* \param index Index of the system
*/
inline void Entity::UnregisterEntityList(EntityList* list)
{
auto it = std::find(m_containedInLists.begin(), m_containedInLists.end(), list);
assert(it != m_containedInLists.end());
// Swap and pop idiom
*it = m_containedInLists.back();
m_containedInLists.pop_back();
}
inline void Entity::UnregisterSystem(SystemIndex index)
{
m_systemBits.UnboundedReset(index);

View File

@ -15,6 +15,8 @@ namespace Ndk
{
class NDK_API EntityList
{
friend Entity;
public:
class iterator;
friend iterator;
@ -23,7 +25,7 @@ namespace Ndk
inline EntityList();
inline EntityList(const EntityList& entityList);
inline EntityList(EntityList&& entityList) noexcept;
~EntityList() = default;
inline ~EntityList();
inline void Clear();
@ -46,6 +48,7 @@ namespace Ndk
private:
inline std::size_t FindNext(std::size_t currentId) const;
inline World* GetWorld() const;
inline void NotifyEntityDestruction(const Entity* entity);
Nz::Bitset<Nz::UInt64> m_entityBits;
World* m_world;

View File

@ -5,7 +5,6 @@
#include <NDK/EntityList.hpp>
#include <Nazara/Core/Error.hpp>
#include <algorithm>
#include "EntityList.hpp"
namespace Ndk
{
@ -30,6 +29,8 @@ namespace Ndk
m_entityBits(entityList.m_entityBits),
m_world(entityList.m_world)
{
for (const Ndk::EntityHandle& entity : *this)
entity->RegisterEntityList(this);
}
/*!
@ -39,6 +40,17 @@ namespace Ndk
m_entityBits(std::move(entityList.m_entityBits)),
m_world(entityList.m_world)
{
for (const Ndk::EntityHandle& entity : *this)
{
entity->UnregisterEntityList(&entityList);
entity->RegisterEntityList(this);
}
}
inline EntityList::~EntityList()
{
for (const Ndk::EntityHandle& entity : *this)
entity->UnregisterEntityList(this);
}
@ -49,6 +61,9 @@ namespace Ndk
*/
inline void EntityList::Clear()
{
for (const Ndk::EntityHandle& entity : *this)
entity->UnregisterEntityList(this);
m_entityBits.Clear();
m_world = nullptr;
}
@ -88,16 +103,19 @@ namespace Ndk
*
* \remark If entity is already contained, no action is performed
* \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities
* \remark It's up to the programmer to remove an entity from this list before its deletion
*/
inline void EntityList::Insert(Entity* entity)
{
NazaraAssert(entity, "Invalid entity");
NazaraAssert(!m_world || entity->GetWorld() == m_world, "Incompatible world");
if (!Has(entity))
{
entity->RegisterEntityList(this);
m_entityBits.UnboundedSet(entity->GetId(), true);
m_world = entity->GetWorld();
}
}
/*!
* \brief Removes the entity from the set
@ -111,7 +129,12 @@ namespace Ndk
*/
inline void EntityList::Remove(Entity* entity)
{
m_entityBits.UnboundedSet(entity->GetId(), false);
if (Has(entity))
{
m_entityBits.Reset(entity->GetId());
entity->UnregisterEntityList(this);
}
}
// STL Interface
@ -140,14 +163,23 @@ namespace Ndk
m_entityBits = entityList.m_entityBits;
m_world = entityList.m_world;
for (const Ndk::EntityHandle& entity : *this)
entity->RegisterEntityList(this);
return *this;
}
inline EntityList& EntityList::operator=(EntityList && entityList) noexcept
inline EntityList& EntityList::operator=(EntityList&& entityList) noexcept
{
m_entityBits = std::move(entityList.m_entityBits);
m_world = entityList.m_world;
for (const Ndk::EntityHandle& entity : *this)
{
entity->UnregisterEntityList(&entityList);
entity->RegisterEntityList(this);
}
return *this;
}
@ -161,6 +193,13 @@ namespace Ndk
return m_world;
}
inline void EntityList::NotifyEntityDestruction(const Entity* entity)
{
assert(Has(entity));
m_entityBits.Reset(entity->GetId());
}
inline EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) :
m_nextEntityId(nextId),
@ -216,6 +255,6 @@ namespace Ndk
using std::swap;
std::swap(lhs.m_nextEntityId, rhs.m_nextEntityId);
swap(lhs.m_nextEntityId, rhs.m_nextEntityId);
}
}

View File

@ -23,6 +23,7 @@ namespace Ndk
Entity::Entity(Entity&& entity) :
HandledObject(std::move(entity)),
m_components(std::move(entity.m_components)),
m_containedInLists(std::move(entity.m_containedInLists)),
m_componentBits(std::move(entity.m_componentBits)),
m_removedComponentBits(std::move(entity.m_removedComponentBits)),
m_systemBits(std::move(entity.m_systemBits)),
@ -176,9 +177,15 @@ namespace Ndk
m_components.clear();
m_componentBits.Reset();
// And then free every handle
// Free every handle
UnregisterAllHandles();
// Remove from every list
for (EntityList* list : m_containedInLists)
list->NotifyEntityDestruction(this);
m_containedInLists.clear();
m_valid = false;
}

View File

@ -57,12 +57,6 @@ namespace Ndk
}
}
m_directionalLights.Remove(entity);
m_drawables.Remove(entity);
m_lights.Remove(entity);
m_particleGroups.Remove(entity);
m_pointSpotLights.Remove(entity);
if (entity->HasComponent<GraphicsComponent>())
{
GraphicsComponent& gfxComponent = entity->GetComponent<GraphicsComponent>();