Merge branch 'entitylist-refactor' of https://github.com/DigitalPulseSoftware/NazaraEngine into entitylist-refactor

This commit is contained in:
Lynix 2017-05-11 20:13:57 +02:00
commit 1b66948213
17 changed files with 316 additions and 121 deletions

View File

@ -9,6 +9,7 @@
#include <Nazara/Core/Bitset.hpp>
#include <NDK/Entity.hpp>
#include <NDK/EntityList.hpp>
#include <vector>
namespace Ndk
@ -33,7 +34,7 @@ namespace Ndk
bool Filters(const Entity* entity) const;
inline const std::vector<EntityHandle>& GetEntities() const;
inline const EntityList& GetEntities() const;
inline SystemIndex GetIndex() const;
inline int GetUpdateOrder() const;
inline float GetUpdateRate() const;
@ -84,12 +85,11 @@ namespace Ndk
static inline bool Initialize();
static inline void Uninitialize();
std::vector<EntityHandle> m_entities;
Nz::Bitset<Nz::UInt64> m_entityBits;
Nz::Bitset<> m_excludedComponents;
mutable Nz::Bitset<> m_filterResult;
Nz::Bitset<> m_requiredAnyComponents;
Nz::Bitset<> m_requiredComponents;
EntityList m_entities;
SystemIndex m_systemIndex;
World* m_world;
bool m_updateEnabled;

View File

@ -56,7 +56,7 @@ namespace Ndk
* \return A constant reference to the list of entities
*/
inline const std::vector<EntityHandle>& BaseSystem::GetEntities() const
inline const EntityList& BaseSystem::GetEntities() const
{
return m_entities;
}
@ -121,10 +121,7 @@ namespace Ndk
inline bool BaseSystem::HasEntity(const Entity* entity) const
{
if (!entity)
return false;
return m_entityBits.UnboundedTest(entity->GetId());
return m_entities.Has(entity);
}
/*!
@ -288,9 +285,7 @@ namespace Ndk
{
NazaraAssert(entity, "Invalid entity");
m_entities.emplace_back(entity);
m_entityBits.UnboundedSet(entity->GetId(), true);
m_entities.Insert(entity);
entity->RegisterSystem(m_systemIndex);
OnEntityAdded(entity);
@ -308,14 +303,7 @@ namespace Ndk
{
NazaraAssert(entity, "Invalid entity");
auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
NazaraAssert(it != m_entities.end(), "Entity is not part of this system");
// To avoid moving a lot of handles, we swap and pop
std::swap(*it, m_entities.back());
m_entities.pop_back(); // We get it out of the vector
m_entityBits.Reset(entity->GetId());
m_entities.Remove(entity);
entity->UnregisterSystem(m_systemIndex);
OnEntityRemoved(entity); // And we alert our callback
@ -360,7 +348,7 @@ namespace Ndk
}
/*!
* \brief Uninitializes the BaseSystem
* \brief Uninitialize the BaseSystem
*/
inline void BaseSystem::Uninitialize()

View File

@ -21,6 +21,8 @@ namespace Ndk
using size_type = std::size_t;
inline EntityList();
inline EntityList(const EntityList& entityList);
inline EntityList(EntityList&& entityList) noexcept;
~EntityList() = default;
inline void Clear();
@ -33,11 +35,14 @@ namespace Ndk
inline void Remove(Entity* entity);
// STL API
inline iterator begin();
inline iterator begin() const;
inline bool empty() const;
inline iterator end();
inline iterator end() const;
inline size_type size() const;
inline EntityList& operator=(const EntityList& entityList);
inline EntityList& operator=(EntityList&& entityList) noexcept;
private:
inline std::size_t FindNext(std::size_t currentId) const;
inline World* GetWorld() const;
@ -46,7 +51,7 @@ namespace Ndk
World* m_world;
};
class EntityList::iterator : public std::iterator<std::forward_iterator_tag, const EntityHandle>
class NDK_API EntityList::iterator : public std::iterator<std::forward_iterator_tag, const EntityHandle>
{
friend EntityList;

View File

@ -16,13 +16,32 @@ namespace Ndk
*/
/*!
* \brief Clears the set from every entities
* \brief Construct a new entity list
*/
inline EntityList::EntityList() :
m_world(nullptr)
{
}
/*!
* \brief Construct a new entity list by copying another one
*/
inline EntityList::EntityList(const EntityList& entityList) :
m_entityBits(entityList.m_entityBits),
m_world(entityList.m_world)
{
}
/*!
* \brief Construct a new entity list by moving a list into this one
*/
inline EntityList::EntityList(EntityList&& entityList) noexcept :
m_entityBits(std::move(entityList.m_entityBits)),
m_world(entityList.m_world)
{
}
/*!
* \brief Clears the set from every entities
*
@ -96,17 +115,17 @@ namespace Ndk
}
// STL Interface
inline EntityList::iterator EntityList::begin()
inline EntityList::iterator EntityList::begin() const
{
return EntityList::iterator(this, m_entityBits.FindFirst());
}
inline bool EntityList::empty() const
{
return m_entityBits.TestAny();
return !m_entityBits.TestAny();
}
inline EntityList::iterator EntityList::end()
inline EntityList::iterator EntityList::end() const
{
return EntityList::iterator(this, m_entityBits.npos);
}
@ -116,6 +135,22 @@ namespace Ndk
return m_entityBits.Count();
}
inline EntityList& EntityList::operator=(const EntityList& entityList)
{
m_entityBits = entityList.m_entityBits;
m_world = entityList.m_world;
return *this;
}
inline EntityList& EntityList::operator=(EntityList && entityList) noexcept
{
m_entityBits = std::move(entityList.m_entityBits);
m_world = entityList.m_world;
return *this;
}
inline std::size_t EntityList::FindNext(std::size_t currentId) const
{
return m_entityBits.FindNext(currentId);

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Jérôme Leclercq
// Copyright (C) 2017 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
@ -10,6 +10,7 @@
#include <NDK/Prerequesites.hpp>
#include <NDK/State.hpp>
#include <memory>
#include <vector>
namespace Ndk
{
@ -25,14 +26,21 @@ namespace Ndk
inline const std::shared_ptr<State>& GetCurrentState() const;
inline bool IsTopState(const State* state) const;
inline std::shared_ptr<State> PopState();
inline bool PopStatesUntil(std::shared_ptr<State> state);
inline void PushState(std::shared_ptr<State> state);
inline void SetState(std::shared_ptr<State> state);
inline bool Update(float elapsedTime);
inline StateMachine& operator=(StateMachine&& fsm) = default;
StateMachine& operator=(const StateMachine&) = delete;
private:
std::shared_ptr<State> m_currentState;
std::shared_ptr<State> m_nextState;
std::vector<std::shared_ptr<State>> m_states;
};
}

View File

@ -3,7 +3,6 @@
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Nazara/Core/Error.hpp>
#include <NDK/StateMachine.hpp>
#include <utility>
namespace Ndk
@ -11,7 +10,7 @@ namespace Ndk
/*!
* \ingroup NDK
* \class Ndk::StateMachine
* \brief NDK class that represents a state machine, to represent the multiple states of your program
* \brief NDK class that represents a state machine, to represent the multiple states of your program as a stack
*/
/*!
@ -23,61 +22,153 @@ namespace Ndk
* \remark Produces a NazaraAssert if nullptr is given
*/
inline StateMachine::StateMachine(std::shared_ptr<State> originalState) :
m_currentState(std::move(originalState))
inline StateMachine::StateMachine(std::shared_ptr<State> originalState)
{
NazaraAssert(m_currentState, "StateMachine must have a state to begin with");
m_currentState->Enter(*this);
NazaraAssert(originalState, "StateMachine must have a state to begin with");
PushState(std::move(originalState));
}
/*!
* \brief Destructs the object
*
* \remark Calls "Leave" on the state
* \remark Calls "Leave" on all the states
*/
inline StateMachine::~StateMachine()
{
m_currentState->Leave(*this);
for (std::shared_ptr<State>& state : m_states)
state->Leave(*this);
}
/*!
* \brief Changes the current state of the machine
* \brief Replaces the current state on the top of the machine
*
* \param state Next state to represent
* \param state State to replace the top one if it is nullptr, no action is performed
*/
inline void StateMachine::ChangeState(std::shared_ptr<State> state)
{
m_nextState = std::move(state);
if (state)
{
PopState();
PushState(std::move(state));
}
}
/*!
* \brief Gets the current state of the machine
* \brief Gets the current state on the top of the machine
* \return A constant reference to the state
*
* \remark The stack is supposed to be non empty, otherwise it is undefined behaviour
*
* \see PopStatesUntil
*/
inline const std::shared_ptr<State>& StateMachine::GetCurrentState() const
{
return m_currentState;
return m_states.back();
}
/*!
* \brief Updates the state
* \return True if update is successful
* \brief Checks whether the state is on the top of the machine
* \return true If it is the case
*
* \param state State to compare the top with
*/
inline bool StateMachine::IsTopState(const State* state) const
{
if (m_states.empty())
return false;
return m_states.back().get() == state;
}
/*!
* \brief Pops the state on the top of the machine
* \return Old state on the top, nullptr if stack was empty
*
* \remark This method can completely empty the stack
*/
inline std::shared_ptr<State> StateMachine::PopState()
{
if (m_states.empty())
return nullptr;
m_states.back()->Leave(*this);
std::shared_ptr<State> oldTopState = std::move(m_states.back());
m_states.pop_back();
return oldTopState;
}
/*!
* \brief Pops all the states of the machine until a specific one is reached
* \return true If that specific state is on top, false if stack is empty
*
* \param state State to find on the stack if it is nullptr, no action is performed
*
* \remark This method can completely empty the stack
*/
inline bool StateMachine::PopStatesUntil(std::shared_ptr<State> state)
{
if (!state)
return false;
while (!m_states.empty() && !IsTopState(state.get()))
PopState();
return !m_states.empty();
}
/*!
* \brief Pushes a new state on the top of the machine
*
* \param state Next state to represent if it is nullptr, it performs no action
*
* \remark Produces a NazaraAssert if the same state is pushed two times on the stack
*/
inline void StateMachine::PushState(std::shared_ptr<State> state)
{
if (state)
{
NazaraAssert(std::find(m_states.begin(), m_states.end(), state) == m_states.end(), "The same state was pushed two times");
m_states.push_back(std::move(state));
m_states.back()->Enter(*this);
}
}
/*!
* \brief Pops every states of the machine to put a new one
*
* \param state State to reset the stack with if it is nullptr, no action is performed
*/
inline void StateMachine::SetState(std::shared_ptr<State> state)
{
if (state)
{
while (!m_states.empty())
PopState();
PushState(std::move(state));
}
}
/*!
* \brief Updates all the states
* \return true If update is successful for everyone of them
*
* \param elapsedTime Delta time used for the update
*/
inline bool StateMachine::Update(float elapsedTime)
{
if (m_nextState)
{
m_currentState->Leave(*this);
m_currentState = std::move(m_nextState);
m_currentState->Enter(*this);
}
return m_currentState->Update(*this, elapsedTime);
return std::all_of(m_states.begin(), m_states.end(), [=](std::shared_ptr<State>& state) {
return state->Update(*this, elapsedTime);
});
}
}

View File

@ -47,7 +47,7 @@ namespace Ndk
void Clear() noexcept;
const EntityHandle& CloneEntity(EntityId id);
const EntityHandle& GetEntity(EntityId id);
inline const EntityHandle& GetEntity(EntityId id);
inline const EntityList& GetEntities() const;
inline BaseSystem& GetSystem(SystemIndex index);
template<typename SystemType> SystemType& GetSystem();
@ -55,7 +55,7 @@ namespace Ndk
inline bool HasSystem(SystemIndex index) const;
template<typename SystemType> bool HasSystem() const;
void KillEntity(Entity* entity);
inline void KillEntity(Entity* entity);
inline void KillEntities(const EntityVector& list);
inline bool IsEntityValid(const Entity* entity) const;

View File

@ -164,18 +164,53 @@ namespace Ndk
return HasSystem(index);
}
/*!
* \brief Marks an entity for deletion
*
* \param Pointer to the entity
*
* \remark If the entity pointer is invalid, nothing is done
* \remark For safety, entities are not killed until the next world update
*/
inline void World::KillEntity(Entity* entity)
{
if (IsEntityValid(entity))
m_killedEntities.UnboundedSet(entity->GetId(), true);
}
/*!
* \brief Kills a set of entities
*
* This function has the same effect as calling KillEntity for every entity contained in the vector
*
* \param list Set of entities to kill
*/
inline void World::KillEntities(const EntityVector& list)
{
for (const EntityHandle& entity : list)
KillEntity(entity);
}
/*!
* \brief Gets an entity
* \return A constant reference to a handle of the entity
*
* \param id Identifier of the entity
*
* \remark Handle referenced by this function can move in memory when updating the world, do not keep a reference to a handle from a world update to another
* \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned
*/
inline const EntityHandle& World::GetEntity(EntityId id)
{
if (IsEntityIdValid(id))
return m_entityBlocks[id]->handle;
else
{
NazaraError("Invalid ID");
return EntityHandle::InvalidHandle;
}
}
/*!
* \brief Checks whether or not an entity is valid
* \return true If it is the case
@ -266,6 +301,7 @@ namespace Ndk
{
m_aliveEntities = std::move(world.m_aliveEntities);
m_dirtyEntities = std::move(world.m_dirtyEntities);
m_entityBlocks = std::move(world.m_entityBlocks);
m_freeIdList = std::move(world.m_freeIdList);
m_killedEntities = std::move(world.m_killedEntities);
m_orderedSystems = std::move(world.m_orderedSystems);
@ -285,7 +321,7 @@ namespace Ndk
inline void World::Invalidate()
{
m_dirtyEntities.Resize(m_entities.size(), false);
m_dirtyEntities.Resize(m_entityBlocks.size(), false);
m_dirtyEntities.Set(true); // Activation of all bits
}

View File

@ -24,6 +24,7 @@ namespace Ndk
HandledObject(std::move(entity)),
m_components(std::move(entity.m_components)),
m_componentBits(std::move(entity.m_componentBits)),
m_removedComponentBits(std::move(entity.m_removedComponentBits)),
m_systemBits(std::move(entity.m_systemBits)),
m_id(entity.m_id),
m_world(entity.m_world),

View File

@ -68,12 +68,14 @@ namespace Ndk
m_freeIdList.pop_back();
entBlock = &m_entities[id];
entBlock->handle.Reset(&entBlock->entity); //< Reset handle (as it was reset when entity got destroyed)
m_entityBlocks[id] = entBlock;
}
else
{
// We allocate a new entity
id = static_cast<Ndk::EntityId>(m_entities.size());
id = static_cast<Ndk::EntityId>(m_entityBlocks.size());
if (m_entities.capacity() > m_entities.size())
{
@ -114,6 +116,7 @@ namespace Ndk
// First, destruction of entities, then handles
// This is made to avoid that handle warn uselessly entities before their destruction
m_entities.clear();
m_entityBlocks.clear();
m_aliveEntities.Clear();
m_dirtyEntities.Clear();
@ -138,7 +141,7 @@ namespace Ndk
return EntityHandle::InvalidHandle;
}
EntityHandle clone = CreateEntity();
const EntityHandle& clone = CreateEntity();
const Nz::Bitset<>& componentBits = original->GetComponentBits();
for (std::size_t i = componentBits.FindFirst(); i != componentBits.npos; i = componentBits.FindNext(i))
@ -150,40 +153,6 @@ namespace Ndk
return GetEntity(clone->GetId());
}
/*!
* \brief Kills an entity
*
* \param Pointer to the entity
*
* \remark No change is done if entity is invalid
*/
void World::KillEntity(Entity* entity)
{
if (IsEntityValid(entity))
m_killedEntities.UnboundedSet(entity->GetId(), true);
}
/*!
* \brief Gets an entity
* \return A constant reference to the modified entity
*
* \param id Identifier of the entity
*
* \remark Produces a NazaraError if entity identifier is not valid
*/
const EntityHandle& World::GetEntity(EntityId id)
{
if (IsEntityIdValid(id))
return m_entities[id].handle;
else
{
NazaraError("Invalid ID");
return EntityHandle::InvalidHandle;
}
}
/*!
* \brief Updates the world
*
@ -205,6 +174,10 @@ namespace Ndk
m_entities.push_back(std::move(*blockPtr));
m_waitingEntities.clear();
// Update entity blocks pointers
for (std::size_t i = 0; i < m_entities.size(); ++i)
m_entityBlocks[i] = &m_entities[i];
}
// Handle killed entities before last call

View File

@ -73,7 +73,7 @@ namespace Nz
std::vector<BillboardData> billboards;
};
typedef std::map<const Material*, BatchedBillboardEntry, MaterialComparator> BatchedBillboardContainer;
using BatchedBillboardContainer = std::map<const Material*, BatchedBillboardEntry, MaterialComparator>;
struct BatchedBillboardPipelineEntry
{
@ -81,7 +81,7 @@ namespace Nz
bool enabled = false;
};
typedef std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator> BillboardPipelineBatches;
using BillboardPipelineBatches = std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator>;
/// Sprites
struct SpriteChain_XYZ_Color_UV
@ -97,7 +97,7 @@ namespace Nz
std::vector<SpriteChain_XYZ_Color_UV> spriteChains;
};
typedef std::map<const Texture*, BatchedSpriteEntry> SpriteOverlayBatches;
using SpriteOverlayBatches = std::map<const Texture*, BatchedSpriteEntry>;
struct BatchedBasicSpriteEntry
{
@ -107,7 +107,7 @@ namespace Nz
bool enabled = false;
};
typedef std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator> SpriteMaterialBatches;
using SpriteMaterialBatches = std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator>;
struct BatchedSpritePipelineEntry
{
@ -115,7 +115,7 @@ namespace Nz
bool enabled = false;
};
typedef std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator> SpritePipelineBatches;
using SpritePipelineBatches = std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator>;
/// Meshes
struct MeshDataComparator
@ -132,7 +132,7 @@ namespace Nz
Spheref squaredBoundingSphere;
};
typedef std::map<MeshData, MeshInstanceEntry, MeshDataComparator> MeshInstanceContainer;
using MeshInstanceContainer = std::map<MeshData, MeshInstanceEntry, MeshDataComparator>;
struct BatchedModelEntry
{
@ -142,7 +142,7 @@ namespace Nz
bool enabled = false;
};
typedef std::map<const Material*, BatchedModelEntry, MaterialComparator> MeshMaterialBatches;
using MeshMaterialBatches = std::map<const Material*, BatchedModelEntry, MaterialComparator>;
struct BatchedMaterialEntry
{
@ -150,7 +150,7 @@ namespace Nz
MeshMaterialBatches materialMap;
};
typedef std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator> MeshPipelineBatches;
using MeshPipelineBatches = std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator>;
struct TransparentModelData
{
@ -160,7 +160,7 @@ namespace Nz
const Material* material;
};
typedef std::vector<std::size_t> TransparentModelContainer;
using TransparentModelContainer = std::vector<std::size_t>;
struct Layer
{

View File

@ -64,10 +64,10 @@ namespace Nz
struct Callback
{
ContactEndCallback endCallback;
ContactPreSolveCallback preSolveCallback;
ContactPostSolveCallback postSolveCallback;
ContactStartCallback startCallback;
ContactEndCallback endCallback = nullptr;
ContactPreSolveCallback preSolveCallback = nullptr;
ContactPostSolveCallback postSolveCallback = nullptr;
ContactStartCallback startCallback = nullptr;
void* userdata;
};

View File

@ -38,7 +38,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
WHEN("We add an entity")
{
const Ndk::EntityHandle& entity = world.CreateEntity();
Ndk::EntityHandle entity = world.CreateEntity();
entity->AddComponent<Ndk::VelocityComponent>();
THEN("System should have it")
@ -50,7 +50,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
WHEN("We add an entity with excluded component")
{
const Ndk::EntityHandle& entity = world.CreateEntity();
Ndk::EntityHandle entity = world.CreateEntity();
entity->AddComponent<Ndk::VelocityComponent>();
entity->AddComponent<Ndk::NodeComponent>();

View File

@ -57,18 +57,18 @@ SCENARIO("Entity", "[NDK][ENTITY]")
{
Ndk::World world;
Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>();
const Ndk::EntityHandle& entity = world.CreateEntity();
Ndk::EntityHandle entity = world.CreateEntity();
WHEN("We add our UpdateComponent")
{
UpdatableComponent& updatableComponent = entity->AddComponent<UpdatableComponent>();
REQUIRE(!updatableComponent.IsUpdated());
CHECK(!updatableComponent.IsUpdated());
THEN("Update the world should update the entity's component")
{
world.Update(1.f);
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
REQUIRE(updatableComponentGet.IsUpdated());
CHECK(updatableComponentGet.IsUpdated());
}
THEN("Update the world should not update the entity's component if it's disabled")
@ -76,14 +76,14 @@ SCENARIO("Entity", "[NDK][ENTITY]")
entity->Enable(false);
world.Update(1.f);
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
REQUIRE(!updatableComponentGet.IsUpdated());
CHECK(!updatableComponentGet.IsUpdated());
}
THEN("We can remove its component")
{
entity->RemoveComponent(Ndk::GetComponentIndex<UpdatableComponent>());
world.Update(1.f);
REQUIRE(!entity->HasComponent<UpdatableComponent>());
CHECK(!entity->HasComponent<UpdatableComponent>());
}
}
@ -94,7 +94,7 @@ SCENARIO("Entity", "[NDK][ENTITY]")
THEN("It's no more valid")
{
REQUIRE(!world.IsEntityValid(entity));
CHECK(!world.IsEntityValid(entity));
}
}
}

View File

@ -7,7 +7,7 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
GIVEN("A world & an entity")
{
Ndk::World world;
const Ndk::EntityHandle& entity = world.CreateEntity();
Ndk::EntityHandle entity = world.CreateEntity();
WHEN("We set the ownership of the entity to our owner")
{
@ -15,14 +15,14 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
THEN("Entity is still valid")
{
REQUIRE(entity.IsValid());
CHECK(entity.IsValid());
}
THEN("Resetting or getting out of scope is no more valid")
{
entityOwner.Reset();
world.Update(1.f);
REQUIRE(!entity.IsValid());
CHECK(!entity.IsValid());
}
}
}

View File

@ -28,21 +28,79 @@ class TestState : public Ndk::State
bool m_isUpdated;
};
class SecondTestState : public Ndk::State
{
public:
void Enter(Ndk::StateMachine& /*fsm*/) override
{
m_isUpdated = false;
}
bool IsUpdated() const
{
return m_isUpdated;
}
void Leave(Ndk::StateMachine& /*fsm*/) override
{
}
bool Update(Ndk::StateMachine& fsm, float /*elapsedTime*/) override
{
if (fsm.IsTopState(this))
m_isUpdated = true;
return true;
}
private:
bool m_isUpdated;
};
SCENARIO("State & StateMachine", "[NDK][STATE]")
{
GIVEN("A statemachine with our TestState")
GIVEN("A statemachine with our test states")
{
std::shared_ptr<TestState> testState = std::make_shared<TestState>();
Ndk::StateMachine stateMachine(testState);
std::shared_ptr<SecondTestState> secondTestState = std::make_shared<SecondTestState>();
Ndk::StateMachine stateMachine(secondTestState);
stateMachine.PushState(testState);
REQUIRE(!testState->IsUpdated());
REQUIRE(!secondTestState->IsUpdated());
WHEN("We update our machine")
{
stateMachine.Update(1.f);
THEN("Our state has been updated")
THEN("Our state on the top has been updated but not the bottom one")
{
REQUIRE(stateMachine.IsTopState(testState.get()));
REQUIRE(!stateMachine.IsTopState(secondTestState.get()));
REQUIRE(testState->IsUpdated());
REQUIRE(!secondTestState->IsUpdated());
}
}
WHEN("We exchange the states' positions while emptying the stack")
{
REQUIRE(stateMachine.PopStatesUntil(secondTestState));
REQUIRE(stateMachine.IsTopState(secondTestState.get()));
std::shared_ptr<Ndk::State> oldState = stateMachine.PopState();
REQUIRE(stateMachine.PopState() == nullptr);
stateMachine.SetState(testState);
stateMachine.PushState(oldState);
stateMachine.Update(1.f);
THEN("Both states should be updated")
{
REQUIRE(!stateMachine.IsTopState(testState.get()));
REQUIRE(stateMachine.IsTopState(secondTestState.get()));
REQUIRE(testState->IsUpdated());
REQUIRE(secondTestState->IsUpdated());
}
}
}

View File

@ -79,7 +79,7 @@ SCENARIO("World", "[NDK][WORLD]")
AND_WHEN("We update our world with our entity")
{
REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem<UpdateSystem>());
const Ndk::EntityHandle& entity = world.CreateEntity();
Ndk::EntityHandle entity = world.CreateEntity();
UpdatableComponent& component = entity->AddComponent<UpdatableComponent>();
THEN("Our entity component must be updated")