// 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 #include #include #include namespace Ndk { /*! * \ingroup NDK * \class Ndk::Entity * \brief NDK class that represents an entity in a world */ /*! * \brief Constructs a Entity object by move semantic * * \param entity Entity to move into this */ 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)), m_id(entity.m_id), m_world(entity.m_world), m_enabled(entity.m_enabled), m_valid(entity.m_valid) { entity.m_world = nullptr; } /*! * \brief Constructs a Entity object linked to a world and with an id * * \param world World in which the entity interact * \param id Identifier of the entity */ Entity::Entity(World* world, EntityId id) : m_id(id), m_world(world) { } /*! * \brief Destructs the object and calls Destroy * * \see Destroy */ Entity::~Entity() { if (m_world && m_valid) Destroy(); } /*! * \brief Adds a component to the entity * \return A reference to the newly added component * * \param componentPtr Component to add to the entity * * \remark Produces a NazaraAssert if component is nullptr */ BaseComponent& Entity::AddComponent(std::unique_ptr&& componentPtr) { NazaraAssert(componentPtr, "Component must be valid"); ComponentIndex index = componentPtr->GetIndex(); // We ensure that the vector has enough space if (index >= m_components.size()) m_components.resize(index + 1); // Affectation and return of the component m_components[index] = std::move(componentPtr); m_componentBits.UnboundedSet(index); m_removedComponentBits.UnboundedReset(index); Invalidate(); // We get the new component and we alert other existing components of the new one BaseComponent& component = *m_components[index].get(); component.SetEntity(this); for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i)) { if (i != index) m_components[i]->OnComponentAttached(component); } return component; } /*! * \brief Clones the entity * \return The clone newly created * * \remark The close is enable by default, even if the original is disabled * \remark Produces a NazaraAssert if the entity is not valid */ const EntityHandle& Entity::Clone() const { NazaraAssert(IsValid(), "Invalid entity"); return m_world->CloneEntity(m_id); } /*! * \brief Kills the entity */ void Entity::Kill() { m_world->KillEntity(this); } /*! * \brief Invalidates the entity */ void Entity::Invalidate() { // We alert everyone that we have been updated m_world->Invalidate(m_id); } /*! * \brief Creates the entity */ void Entity::Create() { m_enabled = true; m_valid = true; } /*! * \brief Destroys the entity */ void Entity::Destroy() { OnEntityDestruction(this); OnEntityDestruction.Clear(); // We prepare components for entity destruction (some components needs this to handle some final callbacks while the entity is still valid) for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i)) m_components[i]->OnEntityDestruction(); // Detach components while they're still attached to systems for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i)) m_components[i]->SetEntity(nullptr); // We alert each system for (std::size_t index = m_systemBits.FindFirst(); index != m_systemBits.npos; index = m_systemBits.FindNext(index)) { auto sysIndex = static_cast(index); if (m_world->HasSystem(sysIndex)) { BaseSystem& system = m_world->GetSystem(sysIndex); system.RemoveEntity(this); } } m_systemBits.Clear(); // Destroy components m_components.clear(); m_componentBits.Reset(); // Free every handle UnregisterAllHandles(); // Remove from every list for (EntityList* list : m_containedInLists) list->NotifyEntityDestruction(this); m_containedInLists.clear(); m_valid = false; } /*! * \brief Destroys a component by index * * \param index Index of the component * * \remark If component is not available, no action is performed */ void Entity::DestroyComponent(ComponentIndex index) { if (HasComponent(index)) { // We get the component and we alert existing components of the deleted one BaseComponent& component = *m_components[index].get(); for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i)) { if (i != index) m_components[i]->OnComponentDetached(component); } component.SetEntity(nullptr); m_components[index].reset(); m_componentBits.Reset(index); } } }