Added systems
It's now officially an ECS, yay! Former-commit-id: e2aacaa5c9fd362921cf3d064e346d11f942bd59
This commit is contained in:
parent
bc40fbb02f
commit
e91313b62d
|
|
@ -12,7 +12,9 @@
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
template<unsigned int N> ComponentId BuildComponentId(const char (&id)[N]);
|
template<unsigned int N> ComponentId BuildComponentId(const char (&id)[N]);
|
||||||
|
template<unsigned int N> SystemId BuildSystemId(const char (&id)[N]);
|
||||||
template<typename ComponentType> constexpr ComponentId GetComponentId();
|
template<typename ComponentType> constexpr ComponentId GetComponentId();
|
||||||
|
template<typename SystemType> constexpr SystemId GetSystemId();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Ndk/Algorithm.inl>
|
#include <Ndk/Algorithm.inl>
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,27 @@ namespace Ndk
|
||||||
return componentId;
|
return componentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<unsigned int N>
|
||||||
|
SystemId BuildSystemId(const char (&id)[N])
|
||||||
|
{
|
||||||
|
static_assert(N-1 <= sizeof(ComponentId), "ID too long for this size of component id");
|
||||||
|
|
||||||
|
ComponentId componentId = 0;
|
||||||
|
for (int i = 0; i < N; ++i)
|
||||||
|
componentId |= static_cast<ComponentId>(id[i]) << i*8;
|
||||||
|
|
||||||
|
return componentId;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ComponentType>
|
template<typename ComponentType>
|
||||||
constexpr ComponentId GetComponentId()
|
constexpr ComponentId GetComponentId()
|
||||||
{
|
{
|
||||||
return ComponentType::ComponentId;
|
return ComponentType::ComponentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename SystemType>
|
||||||
|
constexpr SystemId GetSystemId()
|
||||||
|
{
|
||||||
|
return SystemType::SystemId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NDK_BASESYSTEM_HPP
|
||||||
|
#define NDK_BASESYSTEM_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Core/Bitset.hpp>
|
||||||
|
#include <NDK/EntityHandle.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
class World;
|
||||||
|
|
||||||
|
class NDK_API BaseSystem
|
||||||
|
{
|
||||||
|
friend class Entity;
|
||||||
|
friend World;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BaseSystem(SystemId systemId);
|
||||||
|
virtual ~BaseSystem();
|
||||||
|
|
||||||
|
virtual BaseSystem* Clone() const = 0;
|
||||||
|
|
||||||
|
bool Filters(const EntityHandle& entity) const;
|
||||||
|
|
||||||
|
const std::vector<EntityHandle>& GetEntities() const;
|
||||||
|
SystemId GetId() const;
|
||||||
|
World& GetWorld() const;
|
||||||
|
|
||||||
|
bool HasEntity(const EntityHandle& entity) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<typename ComponentType> void Excludes();
|
||||||
|
template<typename ComponentType1, typename ComponentType2, typename... Rest> void Excludes();
|
||||||
|
void ExcludesComponent(ComponentId componentId);
|
||||||
|
|
||||||
|
template<typename ComponentType> void Requires();
|
||||||
|
template<typename ComponentType1, typename ComponentType2, typename... Rest> void Requires();
|
||||||
|
void RequiresComponent(ComponentId componentId);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AddEntity(const EntityHandle& entity);
|
||||||
|
|
||||||
|
virtual void OnEntityAdded(const EntityHandle& entity);
|
||||||
|
virtual void OnEntityRemoved(const EntityHandle& entity);
|
||||||
|
|
||||||
|
void RemoveEntity(const EntityHandle& entity);
|
||||||
|
|
||||||
|
void SetWorld(World& world);
|
||||||
|
|
||||||
|
std::vector<EntityHandle> m_entities;
|
||||||
|
NzBitset<nzUInt64> m_entityBits;
|
||||||
|
std::unordered_set<ComponentId> m_excludedComponents;
|
||||||
|
std::unordered_set<ComponentId> m_requiredComponents;
|
||||||
|
SystemId m_systemId;
|
||||||
|
World* m_world;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <NDK/BaseSystem.inl>
|
||||||
|
|
||||||
|
#endif // NDK_BASESYSTEM_HPP
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
inline BaseSystem::BaseSystem(SystemId systemId) :
|
||||||
|
m_systemId(systemId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const std::vector<EntityHandle>& BaseSystem::GetEntities() const
|
||||||
|
{
|
||||||
|
return m_entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SystemId BaseSystem::GetId() const
|
||||||
|
{
|
||||||
|
return m_systemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline World& BaseSystem::GetWorld() const
|
||||||
|
{
|
||||||
|
return *m_world;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool BaseSystem::HasEntity(const EntityHandle& entity) const
|
||||||
|
{
|
||||||
|
return m_entityBits.UnboundedTest(entity->GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ComponentType>
|
||||||
|
void BaseSystem::Excludes()
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<BaseComponent, ComponentType>(), "ComponentType is not a component");
|
||||||
|
|
||||||
|
ExcludesComponent(GetComponentId<ComponentType>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ComponentType1, typename ComponentType2, typename... Rest>
|
||||||
|
void BaseSystem::Excludes()
|
||||||
|
{
|
||||||
|
Excludes<ComponentType1>();
|
||||||
|
Excludes<ComponentType2, Rest...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BaseSystem::ExcludesComponent(ComponentId componentId)
|
||||||
|
{
|
||||||
|
m_excludedComponents.insert(componentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ComponentType>
|
||||||
|
void BaseSystem::Requires()
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<BaseComponent, ComponentType>(), "ComponentType is not a component");
|
||||||
|
|
||||||
|
RequiresComponent(GetComponentId<ComponentType>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ComponentType1, typename ComponentType2, typename... Rest>
|
||||||
|
void BaseSystem::Requires()
|
||||||
|
{
|
||||||
|
Requires<ComponentType1>();
|
||||||
|
Requires<ComponentType2, Rest...>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BaseSystem::RequiresComponent(ComponentId componentId)
|
||||||
|
{
|
||||||
|
m_requiredComponents.insert(componentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BaseSystem::AddEntity(const EntityHandle& entity)
|
||||||
|
{
|
||||||
|
m_entities.push_back(entity);
|
||||||
|
m_entityBits.UnboundedSet(entity->GetId(), true);
|
||||||
|
|
||||||
|
entity->RegisterSystem(m_systemId);
|
||||||
|
|
||||||
|
OnEntityAdded(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BaseSystem::RemoveEntity(const EntityHandle& entity)
|
||||||
|
{
|
||||||
|
auto it = std::find(m_entities.begin(), m_entities.end(), entity);
|
||||||
|
NazaraAssert(it != m_entities.end(), "Entity is not part of this system");
|
||||||
|
|
||||||
|
// Pour éviter de déplacer beaucoup de handles, on swap le dernier avec celui à supprimer
|
||||||
|
std::swap(*it, m_entities.back());
|
||||||
|
m_entities.pop_back(); // On le sort du vector
|
||||||
|
|
||||||
|
m_entityBits.Reset(entity->GetId());
|
||||||
|
entity->UnregisterSystem(m_systemId);
|
||||||
|
|
||||||
|
OnEntityRemoved(entity); // Et on appelle le callback
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BaseSystem::SetWorld(World& world)
|
||||||
|
{
|
||||||
|
m_world = &world;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
|
|
@ -20,6 +21,7 @@ namespace Ndk
|
||||||
|
|
||||||
class NDK_API Entity
|
class NDK_API Entity
|
||||||
{
|
{
|
||||||
|
friend class BaseSystem;
|
||||||
friend EntityHandle;
|
friend EntityHandle;
|
||||||
friend World;
|
friend World;
|
||||||
|
|
||||||
|
|
@ -59,10 +61,13 @@ namespace Ndk
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
void RegisterHandle(EntityHandle* handle);
|
void RegisterHandle(EntityHandle* handle);
|
||||||
|
void RegisterSystem(SystemId systemId);
|
||||||
void UnregisterHandle(EntityHandle* handle);
|
void UnregisterHandle(EntityHandle* handle);
|
||||||
|
void UnregisterSystem(SystemId systemId);
|
||||||
|
|
||||||
std::vector<EntityHandle*> m_handles;
|
std::vector<EntityHandle*> m_handles;
|
||||||
std::unordered_map<ComponentId, std::unique_ptr<BaseComponent>> m_components;
|
std::unordered_map<ComponentId, std::unique_ptr<BaseComponent>> m_components;
|
||||||
|
std::unordered_set<SystemId> m_systems;
|
||||||
EntityId m_id;
|
EntityId m_id;
|
||||||
World* m_world;
|
World* m_world;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,11 @@ namespace Ndk
|
||||||
m_handles.push_back(handle);
|
m_handles.push_back(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Entity::RegisterSystem(SystemId systemId)
|
||||||
|
{
|
||||||
|
m_systems.insert(systemId);
|
||||||
|
}
|
||||||
|
|
||||||
inline void Entity::UnregisterHandle(EntityHandle* handle)
|
inline void Entity::UnregisterHandle(EntityHandle* handle)
|
||||||
{
|
{
|
||||||
///DOC: Un handle ne doit être libéré qu'une fois, et doit faire partie de la liste, sous peine de crash
|
///DOC: Un handle ne doit être libéré qu'une fois, et doit faire partie de la liste, sous peine de crash
|
||||||
|
|
@ -94,4 +99,9 @@ namespace Ndk
|
||||||
std::swap(*it, m_handles.back());
|
std::swap(*it, m_handles.back());
|
||||||
m_handles.pop_back();
|
m_handles.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Entity::UnregisterSystem(SystemId systemId)
|
||||||
|
{
|
||||||
|
m_systems.erase(systemId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
using ComponentId = nzUInt32;
|
using ComponentId = nzUInt32;
|
||||||
using EntityId = nzUInt32;
|
using EntityId = nzUInt32;
|
||||||
|
using SystemId = nzUInt32;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // NDK_PREREQUESITES_HPP
|
#endif // NDK_PREREQUESITES_HPP
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NDK_SYSTEM_HPP
|
||||||
|
#define NDK_SYSTEM_HPP
|
||||||
|
|
||||||
|
#include <NDK/BaseSystem.hpp>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
template<typename ComponentType>
|
||||||
|
class System : public BaseSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
System();
|
||||||
|
virtual ~System();
|
||||||
|
|
||||||
|
BaseSystem* Clone() const override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <NDK/System.inl>
|
||||||
|
|
||||||
|
#endif // NDK_SYSTEM_HPP
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
#include <Ndk/Algorithm.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
template<typename SystemType>
|
||||||
|
System<SystemType>::System() :
|
||||||
|
BaseSystem(GetSystemId<SystemType>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SystemType>
|
||||||
|
System<SystemType>::~System() = default;
|
||||||
|
|
||||||
|
template<typename SystemType>
|
||||||
|
BaseSystem* System<SystemType>::Clone() const
|
||||||
|
{
|
||||||
|
///FIXME: Pas encore supporté par GCC (4.9.2)
|
||||||
|
//static_assert(std::is_trivially_copy_constructible<SystemType>::value, "SystemType should be copy-constructible");
|
||||||
|
|
||||||
|
return new SystemType(static_cast<const SystemType&>(*this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,25 +11,38 @@
|
||||||
#include <Nazara/Core/NonCopyable.hpp>
|
#include <Nazara/Core/NonCopyable.hpp>
|
||||||
#include <NDK/Entity.hpp>
|
#include <NDK/Entity.hpp>
|
||||||
#include <NDK/EntityHandle.hpp>
|
#include <NDK/EntityHandle.hpp>
|
||||||
|
#include <NDK/System.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
class NDK_API World : NzNonCopyable
|
class NDK_API World : NzNonCopyable
|
||||||
{
|
{
|
||||||
|
friend Entity;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using EntityList = std::vector<EntityHandle>;
|
using EntityList = std::vector<EntityHandle>;
|
||||||
|
|
||||||
World() = default;
|
World() = default;
|
||||||
~World();
|
~World();
|
||||||
|
|
||||||
|
BaseSystem& AddSystem(std::unique_ptr<BaseSystem>&& system);
|
||||||
|
template<typename SystemType, typename... Args> SystemType& AddSystem(Args&&... args);
|
||||||
|
|
||||||
EntityHandle CreateEntity();
|
EntityHandle CreateEntity();
|
||||||
EntityList CreateEntities(unsigned int count);
|
EntityList CreateEntities(unsigned int count);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
const EntityHandle& GetEntity(EntityId id);
|
const EntityHandle& GetEntity(EntityId id);
|
||||||
|
BaseSystem& GetSystem(SystemId systemId);
|
||||||
|
template<typename SystemType> SystemType& GetSystem();
|
||||||
|
|
||||||
|
bool HasSystem(SystemId systemId) const;
|
||||||
|
template<typename SystemType> bool HasSystem() const;
|
||||||
|
|
||||||
void KillEntity(const EntityHandle& entity);
|
void KillEntity(const EntityHandle& entity);
|
||||||
void KillEntities(const EntityList& list);
|
void KillEntities(const EntityList& list);
|
||||||
|
|
@ -37,9 +50,16 @@ namespace Ndk
|
||||||
bool IsEntityValid(const EntityHandle& entity) const;
|
bool IsEntityValid(const EntityHandle& entity) const;
|
||||||
bool IsEntityIdValid(EntityId id) const;
|
bool IsEntityIdValid(EntityId id) const;
|
||||||
|
|
||||||
|
void RemoveAllSystems();
|
||||||
|
void RemoveSystem(SystemId systemId);
|
||||||
|
template<typename SystemType> void RemoveSystem();
|
||||||
|
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void MarkAllAsDirty();
|
||||||
|
void MarkAsDirty(EntityId id);
|
||||||
|
|
||||||
struct EntityBlock
|
struct EntityBlock
|
||||||
{
|
{
|
||||||
EntityBlock(Entity&& e) :
|
EntityBlock(Entity&& e) :
|
||||||
|
|
@ -53,7 +73,9 @@ namespace Ndk
|
||||||
|
|
||||||
std::vector<EntityId> m_freeIdList;
|
std::vector<EntityId> m_freeIdList;
|
||||||
std::vector<EntityBlock> m_entities;
|
std::vector<EntityBlock> m_entities;
|
||||||
|
std::unordered_map<SystemId, std::unique_ptr<BaseSystem>> m_systems;
|
||||||
EntityList m_aliveEntities;
|
EntityList m_aliveEntities;
|
||||||
|
NzBitset<nzUInt64> m_dirtyEntities;
|
||||||
NzBitset<nzUInt64> m_killedEntities;
|
NzBitset<nzUInt64> m_killedEntities;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,35 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
|
inline BaseSystem& World::AddSystem(std::unique_ptr<BaseSystem>&& system)
|
||||||
|
{
|
||||||
|
NazaraAssert(system, "System must be valid");
|
||||||
|
|
||||||
|
SystemId systemId = system->GetId();
|
||||||
|
|
||||||
|
// Affectation et retour du système
|
||||||
|
m_systems[systemId] = std::move(system);
|
||||||
|
m_systems[systemId]->SetWorld(*this);
|
||||||
|
|
||||||
|
MarkAllAsDirty(); // On force une mise à jour de toutes les entités
|
||||||
|
|
||||||
|
return *m_systems[systemId].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SystemType, typename... Args>
|
||||||
|
SystemType& World::AddSystem(Args&&... args)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a component");
|
||||||
|
|
||||||
|
// Allocation et affectation du component
|
||||||
|
std::unique_ptr<SystemType> ptr(new SystemType(std::forward(args)...));
|
||||||
|
return static_cast<SystemType&>(AddSystem(std::move(ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
inline World::EntityList World::CreateEntities(unsigned int count)
|
inline World::EntityList World::CreateEntities(unsigned int count)
|
||||||
{
|
{
|
||||||
EntityList list;
|
EntityList list;
|
||||||
|
|
@ -17,6 +43,41 @@ namespace Ndk
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline BaseSystem& World::GetSystem(SystemId systemId)
|
||||||
|
{
|
||||||
|
///DOC: Le système doit être présent
|
||||||
|
NazaraAssert(HasSystem(systemId), "This system is not part of the world");
|
||||||
|
|
||||||
|
BaseSystem* system = m_systems[systemId].get();
|
||||||
|
NazaraAssert(system, "Invalid system pointer");
|
||||||
|
|
||||||
|
return *system;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SystemType>
|
||||||
|
SystemType& World::GetSystem()
|
||||||
|
{
|
||||||
|
///DOC: Le système doit être présent
|
||||||
|
static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a system");
|
||||||
|
|
||||||
|
SystemId systemId = GetSystemId<SystemType>();
|
||||||
|
return static_cast<SystemType&>(GetSystem(systemId));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool World::HasSystem(SystemId systemId) const
|
||||||
|
{
|
||||||
|
return m_systems.count(systemId) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SystemType>
|
||||||
|
bool World::HasSystem() const
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a component");
|
||||||
|
|
||||||
|
SystemId systemId = GetSystemId<SystemType>();
|
||||||
|
return HasSystem(systemId);
|
||||||
|
}
|
||||||
|
|
||||||
inline void World::KillEntities(const EntityList& list)
|
inline void World::KillEntities(const EntityList& list)
|
||||||
{
|
{
|
||||||
for (const EntityHandle& entity : list)
|
for (const EntityHandle& entity : list)
|
||||||
|
|
@ -32,4 +93,36 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
return id < m_entities.size() && m_entities[id].entity.IsValid();
|
return id < m_entities.size() && m_entities[id].entity.IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void World::RemoveAllSystems()
|
||||||
|
{
|
||||||
|
m_systems.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void World::RemoveSystem(SystemId systemId)
|
||||||
|
{
|
||||||
|
///DOC: N'a aucun effet si le système n'est pas présent
|
||||||
|
if (HasSystem(systemId))
|
||||||
|
m_systems[systemId].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SystemType>
|
||||||
|
void World::RemoveSystem()
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a system");
|
||||||
|
|
||||||
|
SystemId systemId = GetSystemId<SystemType>();
|
||||||
|
RemoveSystem(systemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void World::MarkAllAsDirty()
|
||||||
|
{
|
||||||
|
m_dirtyEntities.Resize(m_entities.size(), false);
|
||||||
|
m_dirtyEntities.Set(true); // Activation de tous les bits
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void World::MarkAsDirty(EntityId id)
|
||||||
|
{
|
||||||
|
m_dirtyEntities.UnboundedSet(id, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright (C) 2015 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
#include <NDK/BaseSystem.hpp>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
BaseSystem::~BaseSystem()
|
||||||
|
{
|
||||||
|
for (const EntityHandle& entity : m_entities)
|
||||||
|
entity->UnregisterSystem(m_systemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseSystem::Filters(const EntityHandle& entity) const
|
||||||
|
{
|
||||||
|
for (ComponentId component : m_requiredComponents)
|
||||||
|
{
|
||||||
|
if (!entity->HasComponent(component))
|
||||||
|
return false; // Au moins un component requis n'est pas présent
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ComponentId component : m_excludedComponents)
|
||||||
|
{
|
||||||
|
if (entity->HasComponent(component))
|
||||||
|
return false; // Au moins un component exclu est présent
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseSystem::OnEntityAdded(const EntityHandle& entity)
|
||||||
|
{
|
||||||
|
NazaraUnused(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseSystem::OnEntityRemoved(const EntityHandle& entity)
|
||||||
|
{
|
||||||
|
NazaraUnused(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,9 @@ namespace Ndk
|
||||||
// Affectation et retour du component
|
// Affectation et retour du component
|
||||||
m_components[componentId] = std::move(component);
|
m_components[componentId] = std::move(component);
|
||||||
|
|
||||||
|
// On informe le monde que nous avons besoin d'une mise à jour
|
||||||
|
m_world->MarkAsDirty(m_id);
|
||||||
|
|
||||||
return *m_components[componentId].get();
|
return *m_components[componentId].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,13 +56,21 @@ namespace Ndk
|
||||||
void Entity::RemoveAllComponents()
|
void Entity::RemoveAllComponents()
|
||||||
{
|
{
|
||||||
m_components.clear();
|
m_components.clear();
|
||||||
|
|
||||||
|
// On informe le monde que nous avons besoin d'une mise à jour
|
||||||
|
m_world->MarkAsDirty(m_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::RemoveComponent(ComponentId componentId)
|
void Entity::RemoveComponent(ComponentId componentId)
|
||||||
{
|
{
|
||||||
///DOC: N'a aucun effet si le component n'est pas présent
|
///DOC: N'a aucun effet si le component n'est pas présent
|
||||||
if (HasComponent(componentId))
|
if (HasComponent(componentId))
|
||||||
|
{
|
||||||
m_components[componentId].reset();
|
m_components[componentId].reset();
|
||||||
|
|
||||||
|
// On informe le monde que nous avons besoin d'une mise à jour
|
||||||
|
m_world->MarkAsDirty(m_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::Create()
|
void Entity::Create()
|
||||||
|
|
@ -71,6 +82,17 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
|
|
||||||
|
// On informe chaque système
|
||||||
|
for (SystemId systemId : m_systems)
|
||||||
|
{
|
||||||
|
if (m_world->HasSystem(systemId))
|
||||||
|
{
|
||||||
|
BaseSystem& system = m_world->GetSystem(systemId);
|
||||||
|
system.RemoveEntity(CreateHandle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_systems.clear();
|
||||||
|
|
||||||
// On informe chaque handle de notre destruction pour éviter qu'il ne continue de pointer sur nous
|
// On informe chaque handle de notre destruction pour éviter qu'il ne continue de pointer sur nous
|
||||||
for (EntityHandle* handle : m_handles)
|
for (EntityHandle* handle : m_handles)
|
||||||
handle->OnEntityDestroyed();
|
handle->OnEntityDestroyed();
|
||||||
|
|
|
||||||
|
|
@ -106,5 +106,41 @@ namespace Ndk
|
||||||
m_aliveEntities.pop_back();
|
m_aliveEntities.pop_back();
|
||||||
}
|
}
|
||||||
m_killedEntities.Reset();
|
m_killedEntities.Reset();
|
||||||
|
|
||||||
|
for (unsigned int i = m_dirtyEntities.FindFirst(); i != m_dirtyEntities.npos; i = m_dirtyEntities.FindNext(i))
|
||||||
|
{
|
||||||
|
NazaraAssert(i < m_entities.size(), "Entity index out of range");
|
||||||
|
|
||||||
|
EntityBlock& block = m_entities[i];
|
||||||
|
Entity& entity = block.entity;
|
||||||
|
EntityHandle& handle = m_aliveEntities[block.aliveIndex];
|
||||||
|
|
||||||
|
// Aucun intérêt de traiter une entité n'existant plus
|
||||||
|
if (entity.IsValid())
|
||||||
|
{
|
||||||
|
for (auto& systemPair : m_systems)
|
||||||
|
{
|
||||||
|
BaseSystem* system = systemPair.second.get();
|
||||||
|
|
||||||
|
// L'entité est-elle enregistrée comme faisant partie du système ?
|
||||||
|
bool partOfSystem = system->HasEntity(handle);
|
||||||
|
if (system->Filters(handle))
|
||||||
|
{
|
||||||
|
// L'entité doit faire partie du système, est-ce que c'est déjà le cas ?
|
||||||
|
if (!partOfSystem)
|
||||||
|
// Non, rajoutons-là
|
||||||
|
system->AddEntity(handle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// L'entité ne doit pas faire partie du système, était-ce le cas ?
|
||||||
|
if (partOfSystem)
|
||||||
|
// Oui, enlevons-là
|
||||||
|
system->RemoveEntity(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_dirtyEntities.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue