SP3-5 ECS initial commit #5
|
@ -102,10 +102,29 @@
|
|||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponent.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponentGroup.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\Entity\SHEntity.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHFamily.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHHandleGenerator.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseBase.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSet.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSetContainer.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\SHECSMacros.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHComponentManager.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHEntityManager.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHSystem.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHSystemManager.h" />
|
||||
<ClInclude Include="src\Engine\SHEngine.h" />
|
||||
<ClInclude Include="src\SHpch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponentGroup.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\Entity\SHEntity.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\System\SHComponentManager.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\System\SHEntityManager.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\System\SHSystemManager.cpp" />
|
||||
<ClCompile Include="src\Engine\SHEngine.cpp" />
|
||||
<ClCompile Include="src\SHpch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
|
|
|
@ -10,11 +10,30 @@
|
|||
<Filter>Engine</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\SHpch.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponent.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\Components\SHComponentGroup.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\Entity\SHEntity.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHFamily.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHHandleGenerator.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseBase.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSet.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\General\SHSparseSetContainer.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHComponentManager.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHEntityManager.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHSystem.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\System\SHSystemManager.h" />
|
||||
<ClInclude Include="src\Engine\ECS_Base\SHECSMacros.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Engine\SHEngine.cpp">
|
||||
<Filter>Engine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\SHpch.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponentGroup.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\Entity\SHEntity.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\System\SHComponentManager.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\System\SHEntityManager.cpp" />
|
||||
<ClCompile Include="src\Engine\ECS_Base\System\SHSystemManager.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,9 @@
|
|||
#include "SHpch.h"
|
||||
#include "SHComponent.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
SHComponent::~SHComponent()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*********************************************************************
|
||||
* \file SHComponent.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the Component abstract base class.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#ifndef SH_COMPONENT_H
|
||||
#define SH_COMPONENT_H
|
||||
|
||||
#include "SHpch.h"
|
||||
#include "../SHECSMacros.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
||||
class SHComponentManager;
|
||||
|
||||
class SHComponent
|
||||
{
|
||||
friend SHComponentManager;
|
||||
|
||||
private:
|
||||
//The ID of the entity this component belongs to.
|
||||
EntityID entityID;
|
||||
//Whether this entity ID has been set once.
|
||||
//This prevents the Set function from being able to change the entityID once it has been set
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Construct a new SHComponent object
|
||||
* Protected default constructor to make this an abstract base class.
|
||||
***************************************************************************/
|
||||
SHComponent()
|
||||
:entityID(0),isActive(true)
|
||||
{
|
||||
}
|
||||
|
||||
SHComponent(SHComponent const& other)
|
||||
:entityID(other.entityID), isActive(other.isActive)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
//Whether or not this component is active.
|
||||
//Systems using this component should are responsible for checking the active state of the component before running their functionality.
|
||||
bool isActive;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Getter function for the entityID
|
||||
* \return uint32_t
|
||||
* The entityID that this component belongs to.
|
||||
***************************************************************************/
|
||||
uint32_t GetEID()const
|
||||
{
|
||||
return this->entityID;
|
||||
}
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Destroy the SHComponent object
|
||||
* Default destructor for Component Base class
|
||||
***************************************************************************/
|
||||
virtual ~SHComponent();
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* A function that is called when the entity changes its parent.
|
||||
* This can remain empty if nothing has to be done before the parent changes.
|
||||
* This does not change the component that the entity belongs to
|
||||
* The old parent is not passed in here as the old parent might be the root node
|
||||
* in which case there will be no parent.
|
||||
* If needed, the old parent should be deduced using this entityID
|
||||
* \param newParent
|
||||
* EntityID of the new parent.
|
||||
***************************************************************************/
|
||||
virtual void ChangeParent(EntityID newParent)
|
||||
{
|
||||
(void)newParent;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* This is an overloaded function of Change parent when the entity
|
||||
* changes its parent to the root node. (No parent)
|
||||
*
|
||||
***************************************************************************/
|
||||
virtual void ChangeParent()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual void OnDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual void OnCreate()
|
||||
{
|
||||
}
|
||||
|
||||
SHComponent& operator=(SHComponent const& other)
|
||||
{
|
||||
this->entityID = other.GetEID();
|
||||
this->isActive = other.isActive;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,136 @@
|
|||
/*********************************************************************
|
||||
* \file SHComponent.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Implementation for the SHComponentGroup class.
|
||||
* The Component Group aids the engine to sort the components to align
|
||||
* different component type’s data that corresponds to a single entity
|
||||
* in the same index. The component group also ensure that all components
|
||||
* data belonging to the group is moved to the start of the dense array.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#include "SHpch.h"
|
||||
#include "SHComponentGroup.h"
|
||||
#include "../System/SHComponentManager.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
SHComponentGroup::SHComponentGroup()
|
||||
:ownershipType(OWNERSHIP_TYPE::FULL_OWNERSHIP)
|
||||
{
|
||||
componentTypeIDs.reserve(MAX_EID);
|
||||
ownedComponentTypes.reserve(MAX_EID);
|
||||
entityInGroup.reserve(MAX_EID);
|
||||
}
|
||||
|
||||
EntityIndex SHComponentGroup::size() noexcept
|
||||
{
|
||||
return (EntityIndex)entityInGroup.size();
|
||||
}
|
||||
|
||||
bool SHComponentGroup::IsEntityInGroup(EntityID entityID) noexcept
|
||||
{
|
||||
for (auto const& eid : entityInGroup)
|
||||
{
|
||||
if (entityID == eid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHComponentGroup::RemoveEntity(EntityID entityID) noexcept
|
||||
{
|
||||
if (!IsEntityInGroup(entityID))
|
||||
{
|
||||
// This entity has not been added to the group. Ignore it.
|
||||
return false;
|
||||
}
|
||||
|
||||
//This entity is in the group.
|
||||
//Move the placement of the components in all owned component types to the relevant position and remove it from the group.
|
||||
for (auto const& ownedID : ownedComponentTypes)
|
||||
{
|
||||
if (SHComponentManager::ComponentCount_ID(ownedID) > 2)
|
||||
{
|
||||
// There are components that do not belong in the group. Need to swap to the last element
|
||||
SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size() - 1, entityID, ownedID);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<EntityID>::iterator it = entityInGroup.begin(); it != entityInGroup.end(); ++it)
|
||||
{
|
||||
if (*it == entityID)
|
||||
{
|
||||
entityInGroup.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHComponentGroup::Clear() noexcept
|
||||
{
|
||||
entityInGroup.clear();
|
||||
|
||||
}
|
||||
|
||||
bool SHComponentGroup::AddComponentCheck(EntityID entityID, uint32_t componentTypeID) noexcept
|
||||
{
|
||||
if (IsEntityInGroup(entityID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//uint32_t componentID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||
|
||||
//Loops to check if this is one of the owned component type
|
||||
for (auto const& id : componentTypeIDs)
|
||||
{
|
||||
//found it
|
||||
if (id == componentTypeID)
|
||||
{
|
||||
for (auto const& typeID : componentTypeIDs)
|
||||
{
|
||||
if (typeID != componentTypeID && !SHComponentManager::HasComponent_ID(entityID, typeID))
|
||||
{
|
||||
//This entity does not contain all other component types in this group so we don't do anything yet
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//This entity contains all required component types. Add to group and swap in dense
|
||||
//auto& dense = SHComponentManager::GetDense<T>();
|
||||
|
||||
//Loop through all the owned component and sort them.
|
||||
for (auto const& ownedID : ownedComponentTypes)
|
||||
{
|
||||
if (SHComponentManager::ComponentCount_ID(ownedID) > entityInGroup.size() + 1)
|
||||
{
|
||||
// There are components that do not belong in the group. Need to swap to the last element
|
||||
SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size(), entityID, ownedID);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// If dense.size() == entityInGroup.size() + 1.
|
||||
// There is no component that is not in this group for this component type.
|
||||
// Hence no sorting required.
|
||||
|
||||
//Add this entityID to group
|
||||
entityInGroup.push_back(entityID);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//This component type is not in this group.
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
/*********************************************************************
|
||||
* \file SHComponent.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Definition for the SHComponentGroup class.
|
||||
* The Component Group aids the engine to sort the components to align
|
||||
* different component type’s data that corresponds to a single entity
|
||||
* in the same index. The component group also ensure that all components
|
||||
* data belonging to the group is moved to the start of the dense array.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#ifndef SH_COMPONENT_GROUP
|
||||
#define SH_COMPONENT_GROUP
|
||||
|
||||
#include "../SHECSMacros.h"
|
||||
#include "../General/SHFamily.h"
|
||||
#include "SHComponent.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
enum class OWNERSHIP_TYPE
|
||||
{
|
||||
FULL_OWNERSHIP = 0,
|
||||
PARTIAL_OWNERSHIP,
|
||||
NON_OWNERSHIP,
|
||||
OWNERSHIP_MAX
|
||||
};
|
||||
|
||||
|
||||
//template<OWNERSHIP_TYPE ownership>
|
||||
class SHComponentGroup
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
//This vector store the Entity IDs of all entity that belongs to this group.
|
||||
std::vector<EntityID> entityInGroup;
|
||||
|
||||
|
||||
//template<>
|
||||
//bool CheckAddComponent();
|
||||
SHComponentGroup();
|
||||
~SHComponentGroup() = default;
|
||||
|
||||
//friends SHComponentManager to allow ECSCore to create componentgroups
|
||||
friend class SHComponentManager;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the number of entity in the group.
|
||||
* \return
|
||||
* Number of entity in the group.
|
||||
***************************************************************************/
|
||||
EntityIndex size() noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Check if a entity is already in the group.
|
||||
* \param entityID
|
||||
* The entity ID of the entity
|
||||
* \return
|
||||
* true if the entity belongs to the group
|
||||
***************************************************************************/
|
||||
bool IsEntityInGroup(EntityID entityID) noexcept;
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Checks whether the entity has fulfilled the requirements to be added into
|
||||
* the Component Group after adding a specified Component Type.
|
||||
* @tparam T
|
||||
* Component type to be added
|
||||
* \param entityID
|
||||
* EntityID of the entity to be added
|
||||
***************************************************************************/
|
||||
bool AddComponentCheck(EntityID entityID, uint32_t componentTypeID) noexcept;
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Check if the Component type is in the component group and if the entity is in the group
|
||||
* Remove it from the group if found.
|
||||
* This does not handle the removal from the dense array in the sparse set.
|
||||
* @tparam T
|
||||
* Component type to be removed
|
||||
* \param entityID
|
||||
* EntityID of the entity
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_base_of_v<SHComponent, T>, bool> RemoveComponentCheck(EntityID entityID) noexcept
|
||||
{
|
||||
|
||||
if (!IsEntityInGroup(entityID))
|
||||
{
|
||||
// This entity has not been added to the group. Ignore it.
|
||||
return false;
|
||||
}
|
||||
bool typeFound = false;
|
||||
uint32_t componentID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||
for (auto const& id : componentTypeIDs)
|
||||
{
|
||||
if (id == componentID)
|
||||
{
|
||||
typeFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (typeFound == false)
|
||||
{
|
||||
return false; //This type is not something this group needs to care about.
|
||||
}
|
||||
|
||||
//This entity is in the group.
|
||||
//Move the placement of the components in all owned component types to the relevant position and remove it from the group.
|
||||
for (auto const& ownedID : ownedComponentTypes)
|
||||
{
|
||||
if (SHComponentManager::ComponentCount_ID(ownedID) > entityInGroup.size() + 1)
|
||||
{
|
||||
// There are components that do not belong in the group. Need to swap to the last element
|
||||
SHComponentManager::SwapInDenseByIndexHash_ID((EntityIndex)entityInGroup.size() - 1, entityID, ownedID);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<EntityID>::iterator it = entityInGroup.begin(); it != entityInGroup.end(); ++it)
|
||||
{
|
||||
if (*it == entityID)
|
||||
{
|
||||
entityInGroup.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Checks if this entity is in the Component Group and remove it if found.
|
||||
* This does not handle the removal from the dense array in the sparse set.
|
||||
* \param entityID
|
||||
* EntityID of the entity
|
||||
***************************************************************************/
|
||||
bool RemoveEntity(EntityID entityID) noexcept;
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Resets the Component Group by clearing all entity in group.
|
||||
* This will not change the Component Types that belong in the group but
|
||||
* only clear the entity that belongs to the group.
|
||||
* This is used for scene transition where all entities are cleared.
|
||||
***************************************************************************/
|
||||
void Clear() noexcept;
|
||||
|
||||
|
||||
private:
|
||||
OWNERSHIP_TYPE ownershipType;
|
||||
|
||||
protected:
|
||||
|
||||
//This vector stores all IDs of all the component type that belongs to this group.
|
||||
//This will be assigned when the group gets created and used by the group themselves when they for add/remove components.
|
||||
std::vector<uint32_t> componentTypeIDs;
|
||||
|
||||
//This vector stores the IDs of all the component type that this group owns.
|
||||
//Each component type can only be owned by one group.
|
||||
std::vector<uint32_t> ownedComponentTypes;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,74 @@
|
|||
/*********************************************************************
|
||||
* \file SHEntity.cpp
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Definition of function used in SHEntity class.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
#include "SHpch.h"
|
||||
#include "SHEntity.h"
|
||||
#include "../System/SHEntityManager.h"
|
||||
//#include "Scene/SHSceneGraph.h"
|
||||
#include "../System/SHComponentManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
||||
SHEntity::SHEntity()
|
||||
:entityID(),isActive(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SHEntity::~SHEntity()
|
||||
{
|
||||
|
||||
//SHEntityManager::RemoveEntity(this->entityID);
|
||||
}
|
||||
|
||||
EntityID SHEntity::GetEID() noexcept
|
||||
{
|
||||
return this->entityID;
|
||||
}
|
||||
|
||||
void SHEntity::SetActive(bool active) noexcept
|
||||
{
|
||||
isActive = active;
|
||||
SHComponentManager::SetActive(entityID, active);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SHEntity::SetParent(SHEntity* newParent) noexcept
|
||||
{
|
||||
(void)newParent;
|
||||
//TODO
|
||||
}
|
||||
|
||||
void SHEntity::SetParent(EntityID newParentID) noexcept
|
||||
{
|
||||
(void)newParentID;
|
||||
//TODO
|
||||
}
|
||||
|
||||
SHEntity* SHEntity::GetParent() noexcept
|
||||
{
|
||||
//TODO
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
std::vector<SHEntity*>const& SHEntity::GetChildren() noexcept
|
||||
{
|
||||
//TODO
|
||||
return std::vector<SHEntity*>{};
|
||||
}
|
||||
|
||||
std::vector<EntityID>const& SHEntity::GetChildrenID() noexcept
|
||||
{
|
||||
return std::vector<EntityID>{};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*********************************************************************
|
||||
* \file SHEntity.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the Entity abstract base class.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SH_ENTITY_H
|
||||
#define SH_ENTITY_H
|
||||
|
||||
#include "../SHECSMacros.h"
|
||||
#include "../Components/SHComponent.h"
|
||||
#include "../System/SHComponentManager.h"
|
||||
//#include "../../Scene/SHSceneNode.h"
|
||||
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHComponentManager;
|
||||
class SHEntityManager;
|
||||
|
||||
class SHEntity
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Friends with SHEntityManger.
|
||||
* This allows SHEntityManager to generate a unique entityID for the entity
|
||||
* upon creation.
|
||||
* .
|
||||
***************************************************************************/
|
||||
friend SHEntityManager;
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Construct a new SHEntity object
|
||||
* Default constructor for the Entity Object.
|
||||
* Entities are given their entityID here.
|
||||
***************************************************************************/
|
||||
SHEntity();
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Destroy the SHEntity object
|
||||
* Default destructor for the Entity object.
|
||||
* Removes the entityID and queue it for recycling.
|
||||
***************************************************************************/
|
||||
virtual ~SHEntity();
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Get the Component object
|
||||
* A templated GetComponent_s function that calls GetComponent_s from SHComponentManager.
|
||||
* This is for ease of use.
|
||||
* @tparam T
|
||||
* The type of the Component we are trying to get.
|
||||
* \return
|
||||
* A pointer to the Component we are trying to get.
|
||||
* Returns nullptr if the entity does not have such Component.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_base_of_v<SHComponent, T>, T*> GetComponent() noexcept
|
||||
{
|
||||
|
||||
return SHComponentManager::GetComponent_s<T>(entityID);
|
||||
//return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Getter function for the entityID
|
||||
* \return uint32_t
|
||||
* The entityID of this Entity object.
|
||||
***************************************************************************/
|
||||
EntityID GetEID() noexcept;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Set the Active object
|
||||
* Sets the isActive of all Components in this entity.
|
||||
* This is done through SHComponentManager and this function is for ease of use.
|
||||
* If derived classes of Entity overloads this function, they are expected to
|
||||
* call this function using SHEntity::SetActive(active) to change the active of
|
||||
* all components
|
||||
* \param active
|
||||
* The active state to change all components in this entity.
|
||||
***************************************************************************/
|
||||
virtual void SetActive(bool active) noexcept;
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Change the parent of the entity object in the scene graph.
|
||||
* This command will be stored in a queue and only applied when
|
||||
* SHSceneGraph::UpdateHierachy is called.
|
||||
* \param newParent
|
||||
* A pointer to the new parent entity.
|
||||
* Pass a nullptr to attach this entity to the root node instead.
|
||||
***************************************************************************/
|
||||
void SetParent(SHEntity* newParent = nullptr) noexcept;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Change the parent of the entity object in the scene graphj.
|
||||
* This command will be stored in a queue and only applied when
|
||||
* SHSceneGraph::UpdateHierachy is called
|
||||
* This is the overloaded version of the function that takes in a
|
||||
* EntityID instead. This cannot be used to attach to the root node.
|
||||
* \param newParentID
|
||||
* The entityID of the new parent.
|
||||
***************************************************************************/
|
||||
void SetParent(EntityID newParentID) noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get a pointer to the parent entity.
|
||||
* \return
|
||||
* Returns a pointer to the parent entity.
|
||||
* Returns a nullptr if the parent node is the root node.
|
||||
***************************************************************************/
|
||||
SHEntity* GetParent() noexcept;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get a vector of SHEntity pointers of the children belonging to this entity.
|
||||
* \return
|
||||
* Return a vector of SHEntity pointers of the children belonging to this entity.
|
||||
***************************************************************************/
|
||||
std::vector<SHEntity*>const& GetChildren() noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get a vector of EntityID of the children belonging to this entity.
|
||||
* \return
|
||||
* return a vector of EntityID of the children belonging to this entity.
|
||||
***************************************************************************/
|
||||
std::vector<EntityID>const& GetChildrenID() noexcept;
|
||||
|
||||
|
||||
std::string name;
|
||||
bool isActive;
|
||||
|
||||
|
||||
private:
|
||||
//The identifier of the entity.
|
||||
//This is split into 2 x 16-bits that represents version and index respectively
|
||||
//Index is used by the engine to index the entity.
|
||||
//Version is used by the engine to recycle the index of the entity.
|
||||
EntityID entityID;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,88 @@
|
|||
/*********************************************************************
|
||||
* \file SHFamily.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the SHFamily template class.
|
||||
* This class is to create a unique identifier for each derived class type.
|
||||
* Example: Each Component type (SHTransformComponent / SHRenderableComponent)
|
||||
* will have a different identifier generated by this class.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SH_FAMILY_H
|
||||
#define SH_FAMILY_H
|
||||
|
||||
#include "../SHECSMacros.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
template<typename BaseClass>
|
||||
class SHFamilyID
|
||||
{
|
||||
private:
|
||||
//this is used to keep track of the new current ID to be assign to a new Derived class type.
|
||||
static ComponentTypeID currentID;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Construct a new SHFamilyID object
|
||||
* Private constructor.
|
||||
* No objects of this type should be made.
|
||||
* Only use the static functions of this class
|
||||
***************************************************************************/
|
||||
SHFamilyID()
|
||||
{
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Destroy the SHFamilyID object
|
||||
* Private destructor.
|
||||
* No objects of this type should be made.
|
||||
* Only use the static functions of this class
|
||||
***************************************************************************/
|
||||
virtual ~SHFamilyID()
|
||||
{
|
||||
}
|
||||
public:
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Checks if this identifier is cuurrently in use / valid.
|
||||
* \param id
|
||||
* Identifier to check for.
|
||||
* \return bool
|
||||
* true if the identifier is currently in use.
|
||||
* false if the identifier is not in use.
|
||||
***************************************************************************/
|
||||
static bool IsValidID(ComponentTypeID id) noexcept
|
||||
{
|
||||
return(id < currentID);
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Get the ID of a derived class type.
|
||||
* Example of function call to this function should be:
|
||||
* SHFamily<SHComponent>::GetID<SHTransformComponent>();
|
||||
* @tparam DerivedClass
|
||||
* The derived class type that we are trying to get the ID of.
|
||||
***************************************************************************/
|
||||
template<typename DerivedClass>
|
||||
static ENABLE_IF_DERIVED(ComponentTypeID, BaseClass, DerivedClass) GetID() noexcept
|
||||
{
|
||||
//The first time a new derived class type call this get id, it will initialize id using the currentID from familyID class.
|
||||
static ComponentTypeID id = currentID++;
|
||||
return id;
|
||||
}
|
||||
};
|
||||
//initialize currentID as 0
|
||||
template<typename BaseClass>
|
||||
ComponentTypeID SHFamilyID<BaseClass>::currentID = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,305 @@
|
|||
/*********************************************************************
|
||||
* \file SHHandleGenerator.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
*
|
||||
* \brief Declaration for the SHHandleGenerator class.
|
||||
* Generates a unique identifier/handle for objects.
|
||||
* This is different from SHFamily which is meant to generate identifier for object types.
|
||||
*
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
#ifndef SH_HANDLE_GENERATOR_H
|
||||
#define SH_HANDLE_GENERATOR_H
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include "../SHECSMacros.h"
|
||||
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*********************************************************************
|
||||
* \brief
|
||||
* Generates a unique handle of HandleType type.
|
||||
* The first half of the bits will be used for version. This is used for recyling the IDs.
|
||||
* The second half of the bits will be used for the index, this is also used as its ID.
|
||||
*
|
||||
* HandleType should always be twice the size of IndexType
|
||||
*********************************************************************/
|
||||
|
||||
template <typename HandleType, typename IndexType>
|
||||
class SHHandleGenerator
|
||||
{
|
||||
private:
|
||||
//List of all the handles in use. Handles that are deleted are still stored here.
|
||||
std::vector<HandleType> handleList;
|
||||
//The next handle to be used.
|
||||
HandleType nextRecycle;
|
||||
//The total number of handles that are currently deleted and waiting to be recycled.
|
||||
HandleType recycleCounter;
|
||||
|
||||
//The Mask is variable is used to easily separate the version and index via bit masking (bitwise &).
|
||||
|
||||
|
||||
//The index mask is used to identify the index.
|
||||
//(1<<16) - 1. Shift 1 bit to the left 16 times and -1. This leaves the first 16 bits as 0 and the -1 makes the second 16 bits all 1.
|
||||
static const HandleType indexMask = (1 << sizeof(IndexType) * 8) - 1;
|
||||
|
||||
//using the bitwise NOT, invert the index mask to get the version mask.
|
||||
static const HandleType versionMask = ~indexMask;
|
||||
|
||||
public:
|
||||
/*!*************************************************************************
|
||||
* \brief Construct a new SHHandleGenerator object
|
||||
* default constructor for the HandleGenerator object.
|
||||
***************************************************************************/
|
||||
SHHandleGenerator()
|
||||
:nextRecycle(0),recycleCounter(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Destroy the SHHandleGenerator object
|
||||
* Default destructor for the HandleGenerator object.
|
||||
***************************************************************************/
|
||||
~SHHandleGenerator() = default;
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Combines the 16-bit version and 16-bit index to make a 32-bit handle.
|
||||
* \param verison
|
||||
* The 16-bit version
|
||||
* \param index
|
||||
* The 16-bit index
|
||||
* \return HandleType
|
||||
* The resultant Handle
|
||||
***************************************************************************/
|
||||
static HandleType GetHandle(IndexType version, IndexType index) noexcept
|
||||
{
|
||||
return (version << sizeof(IndexType) * 8) | index;
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Gets the 16-bit version from the 32-bit handle
|
||||
* \param handle
|
||||
* The 32-bit handle
|
||||
* \return IndexType
|
||||
* The 16-bit version
|
||||
***************************************************************************/
|
||||
static IndexType GetVersion(HandleType handle) noexcept
|
||||
{
|
||||
return handle >> sizeof(IndexType) * 8;
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Gets the 16-bit index from the 32-bit handle
|
||||
* \param handle
|
||||
* The 32-bit handle
|
||||
* \return IndexType
|
||||
* The 16-bit index
|
||||
***************************************************************************/
|
||||
static IndexType GetIndex(HandleType handle) noexcept
|
||||
{
|
||||
return handle & indexMask;
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Checks if the current handle is still valid. This checks if the index
|
||||
* of the handle is in use, then checks if the version of the current index
|
||||
* matches the handle we are checking for.
|
||||
* \param handle
|
||||
* The handle to check for.
|
||||
* \return bool
|
||||
* True if the handle is still valid. False if the handle has been removed
|
||||
* or not in use.
|
||||
***************************************************************************/
|
||||
bool IsValid(HandleType handle) noexcept
|
||||
{
|
||||
IndexType index = GetIndex(handle);
|
||||
if (index >= (IndexType)handleList.size()) // handle is out of range of intialized index
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (handleList[index] == handle); // this will check if the current handle at that index has been removed.
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the number of active handles.
|
||||
* \return
|
||||
* Number of active handles.
|
||||
***************************************************************************/
|
||||
IndexType GetActiveHandleCount() noexcept
|
||||
{
|
||||
return (IndexType)(handleList.size() - recycleCounter);
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Request the Generator for a new handle. This will provide recycled index
|
||||
* if available
|
||||
* \return HandleType
|
||||
* The new handle.
|
||||
***************************************************************************/
|
||||
HandleType GetNewHandle() noexcept
|
||||
{
|
||||
HandleType result;
|
||||
|
||||
//Check if there is any index waiting to be recycled
|
||||
if (recycleCounter == 0) // nothing to be recycled. Make a new one
|
||||
{
|
||||
result = GetHandle(0, (IndexType)handleList.size());
|
||||
handleList.push_back(result);
|
||||
return result;
|
||||
}
|
||||
//There is a index waiting to be recycled.
|
||||
result = nextRecycle;
|
||||
IndexType index = GetIndex(nextRecycle);
|
||||
//updates the next recycle.
|
||||
nextRecycle = handleList[index];
|
||||
handleList[index] = result;
|
||||
--recycleCounter;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Removes a handle and make it invalid and queue it for recycling.
|
||||
* \param handle
|
||||
* The handle to remove.
|
||||
***************************************************************************/
|
||||
void RemoveHandle(HandleType handle) noexcept
|
||||
{
|
||||
if (!IsValid(handle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IndexType index = GetIndex(handle);
|
||||
IndexType version = GetVersion(handle);
|
||||
|
||||
//set the handle at the current index to the next thing to be recycled.
|
||||
handleList[index] = nextRecycle;
|
||||
|
||||
//set the next recycle to be the thing that was just deleted with its version incremented.
|
||||
nextRecycle = GetHandle(version + 1, index);
|
||||
++recycleCounter;
|
||||
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Clears all the handles in use and Resets the handle generation.
|
||||
***************************************************************************/
|
||||
void ClearAllHandles() noexcept
|
||||
{
|
||||
handleList.clear();
|
||||
nextRecycle = 0;
|
||||
recycleCounter = 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Attempts to claim a specified handle. If the handle is available, the
|
||||
* generator will mark it as claimed and return true.
|
||||
* Updates recycles accordingly when adding extra padding to the handle list.
|
||||
*
|
||||
* \param handle
|
||||
* The handle to claim
|
||||
*
|
||||
* \return
|
||||
* true if the handle is available to claim.
|
||||
***************************************************************************/
|
||||
bool ClaimHandle(HandleType handle) noexcept
|
||||
{
|
||||
IndexType index = GetIndex(handle);
|
||||
|
||||
if (handleList.size() <= index || GetIndex(handleList[index]) != index)
|
||||
{
|
||||
//This index is currently not in use
|
||||
|
||||
if (index >= handleList.size())
|
||||
{
|
||||
IndexType size = (IndexType)handleList.size();
|
||||
|
||||
for (IndexType i = 0; i < index - size; ++i)
|
||||
{
|
||||
handleList.push_back((IndexType)handleList.size());
|
||||
|
||||
HandleType back = handleList.back();
|
||||
//set the handle at the current index to the next thing to be recycled.
|
||||
if (recycleCounter > 0)
|
||||
handleList.back() = nextRecycle;
|
||||
else
|
||||
{
|
||||
handleList.back() = (HandleType)-1;
|
||||
}
|
||||
|
||||
//set the next recycle to be the thing that was just deleted with its version incremented.
|
||||
nextRecycle = GetHandle(0, GetIndex(back));
|
||||
++recycleCounter;
|
||||
}
|
||||
handleList.push_back(handle);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index == GetIndex(nextRecycle))
|
||||
{
|
||||
index = GetIndex(nextRecycle);
|
||||
//updates the next recycle.
|
||||
nextRecycle = handleList[index];
|
||||
handleList[index] = handle;
|
||||
--recycleCounter;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (recycleCounter > 0)
|
||||
{
|
||||
HandleType recycle = handleList[index];
|
||||
IndexType recycleIndex = GetIndex(nextRecycle);
|
||||
HandleType i = 0;
|
||||
while (i < recycleCounter)
|
||||
{
|
||||
if (GetIndex(handleList[recycleIndex]) == index)
|
||||
break;
|
||||
recycleIndex = GetIndex(handleList[recycleIndex]);
|
||||
++i;
|
||||
}
|
||||
--recycleCounter;
|
||||
if (recycleCounter > 0 && recycleIndex < handleList.size())
|
||||
handleList[recycleIndex] = recycle;
|
||||
}
|
||||
handleList[index] = handle;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef SHHandleGenerator<EntityID, EntityIndex> EntityHandleGenerator;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/*********************************************************************
|
||||
* \file SHSparseBase.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the SHSparseBase class.
|
||||
* This is an abstract class for the SHSparseSet template class.
|
||||
* This allows the SHSparseSetContainer class to store SparseSet of different types.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SH_SPARSE_BASE_H
|
||||
#define SH_SPARSE_BASE_H
|
||||
|
||||
#include "../SHECSMacros.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
||||
class SHSparseBase
|
||||
{
|
||||
protected:
|
||||
SHSparseBase() = default;
|
||||
|
||||
public:
|
||||
virtual ~SHSparseBase() = default;
|
||||
|
||||
virtual void Remove(EntityIndex hash) { (void)hash; };
|
||||
|
||||
virtual void Clear() {};
|
||||
|
||||
virtual void Swap(EntityIndex hash1, EntityIndex hash2) { (void)hash1; (void)hash2; };
|
||||
|
||||
virtual void SwapIndexHash(EntityIndex index1, EntityIndex hash) { (void)index1; (void)hash; };
|
||||
|
||||
virtual bool Has(EntityIndex hash) = 0;
|
||||
|
||||
virtual void* Get(EntityIndex hash) { (void)hash; return nullptr; };
|
||||
|
||||
virtual void Add(EntityIndex hash) { (void)hash; };
|
||||
|
||||
virtual EntityIndex Count() = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,356 @@
|
|||
/*********************************************************************
|
||||
* \file SHSparseSet.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the SHSparseSet template class
|
||||
* This is a container that allows for fast iteration due to contiguous memory
|
||||
* storage while having fast lookup time at the cost of memory usage.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
#ifndef SH_SPARSE_SET_H
|
||||
#define SH_SPARSE_SET_H
|
||||
|
||||
#include "../SHECSMacros.h"
|
||||
#include "../General/SHSparseBase.h"
|
||||
#include "../General/SHHandleGenerator.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
template <typename T, EntityIndex MAX>
|
||||
class SHSparseSet: public SHSparseBase
|
||||
{
|
||||
private:
|
||||
//Dense array of type T
|
||||
std::vector<T> denseArray;
|
||||
//This array stores the key of the corresponding element in the dense array. (eg. entity ID)
|
||||
std::vector<EntityIndex> denseIndexArray;
|
||||
|
||||
//Sparse Array. This array helps with look up
|
||||
EntityIndex sparseArray[MAX];
|
||||
|
||||
public:
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Construct a new SHSparseSet object
|
||||
* Default constructor for the SparseSet class.
|
||||
***************************************************************************/
|
||||
SHSparseSet()
|
||||
{
|
||||
for (EntityIndex i = 0; i < MAX; ++i)
|
||||
{
|
||||
sparseArray[i] = UINT16_MAX;
|
||||
}
|
||||
|
||||
denseArray.reserve(MAX);
|
||||
denseIndexArray.reserve(MAX);
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief Destroy the SHSparseSet object
|
||||
* Default destructor for the SparseSet class.
|
||||
***************************************************************************/
|
||||
virtual ~SHSparseSet()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Clears all elements in the current SparseSet and resets the sparseArray.
|
||||
***************************************************************************/
|
||||
void Clear() noexcept
|
||||
{
|
||||
denseArray.clear();
|
||||
denseIndexArray.clear();
|
||||
for (EntityIndex i = 0; i < MAX; ++i)
|
||||
{
|
||||
sparseArray[i] = UINT16_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Check is the specified hash is in range of the sparseSet.
|
||||
* \param hash
|
||||
* Hash to check for.
|
||||
* \return bool
|
||||
* true if the specified hash is in range of the spraseSet.
|
||||
***************************************************************************/
|
||||
bool IsValid(EntityIndex hash) noexcept
|
||||
{
|
||||
return (hash < MAX);
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Checks if this sparseSet contains an element with specified hash.
|
||||
* \param hash
|
||||
* The hash to check for.
|
||||
* \return bool
|
||||
* true if the element with this hash is found. false if no such element is found.
|
||||
***************************************************************************/
|
||||
virtual bool Has(EntityIndex hash) noexcept
|
||||
{
|
||||
//Check if the hash passed in is within range.
|
||||
if (!IsValid(hash) || sparseArray[hash] == UINT16_MAX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (denseIndexArray[sparseArray[hash]] == hash);
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Get a pointer to the element with the specified hash.
|
||||
|
||||
* This is the safe version which does a Has() check and return a nullptr
|
||||
* if it does not have such an Element
|
||||
*
|
||||
* \param hash
|
||||
* The hash of the element to look for.
|
||||
* \return T*
|
||||
* returns a pointer to the element with the specified hash if found.
|
||||
* returns a nullptr if no such element is found.
|
||||
***************************************************************************/
|
||||
T* GetElement_s(EntityIndex hash) noexcept
|
||||
{
|
||||
if (!Has(hash))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &denseArray[sparseArray[hash]];
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Get a pointer to the element with the specified hash.
|
||||
|
||||
* This bypasses the Has() check and assumes that the hash has a Element
|
||||
* in the dense array.
|
||||
*
|
||||
* \param hash
|
||||
* The hash of the element to look for.
|
||||
* \return T*
|
||||
* returns a pointer to the element with the specified hash if found.
|
||||
* returns a nullptr if no such element is found.
|
||||
***************************************************************************/
|
||||
T* GetElement(EntityIndex hash) noexcept
|
||||
{
|
||||
return &denseArray[sparseArray[hash]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Operator overload for the subscript operator.
|
||||
* Gets the element by reference with the hash specified in the subscript.
|
||||
* This does not handle out of range exceptions.
|
||||
* \param hash
|
||||
* The hash of the element we are trying to get
|
||||
* \return T&
|
||||
* A reference to the element found.
|
||||
***************************************************************************/
|
||||
T& operator[](EntityIndex hash) noexcept
|
||||
{
|
||||
return denseArray[sparseArray[hash]];
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Get the number of elements in the current SparseSet
|
||||
* \return uint16_t
|
||||
* The number of elements in the SparseSet.
|
||||
***************************************************************************/
|
||||
virtual EntityIndex Count() noexcept
|
||||
{
|
||||
return (EntityIndex)denseArray.size();
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Getter function for the dense array.
|
||||
* \return std::vector<T>&
|
||||
* return a reference to the dense array.
|
||||
***************************************************************************/
|
||||
std::vector<T>& GetDense() noexcept
|
||||
{
|
||||
return denseArray;
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Const getter function for the dense array.
|
||||
* \return std::vector<T>&
|
||||
* return a const reference to the dense array.
|
||||
***************************************************************************/
|
||||
const std::vector<T> GetDense() const noexcept
|
||||
{
|
||||
return denseArray;
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Swaps two elements in the dense array.
|
||||
* This only swaps their position in the dense array and updates their
|
||||
* Sparse index reference in the sprase array accordingly.
|
||||
* This DOES NOT change the hash of the elements.
|
||||
* \param hash1
|
||||
* Hash of the first element
|
||||
* \param hash2
|
||||
* Hash of the second element
|
||||
***************************************************************************/
|
||||
virtual void Swap(EntityIndex hash1, EntityIndex hash2) noexcept
|
||||
{
|
||||
if (!Has(hash1) || !Has(hash2) || hash1 == hash2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
T tempElement = denseArray[sparseArray[hash1]];
|
||||
EntityIndex tempIndex = denseIndexArray[sparseArray[hash1]];
|
||||
EntityIndex tempSparse = sparseArray[hash1];
|
||||
|
||||
denseArray[sparseArray[hash1]] = denseArray[sparseArray[hash2]];
|
||||
denseIndexArray[sparseArray[hash1]] = denseIndexArray[sparseArray[hash2]];
|
||||
sparseArray[hash1] = sparseArray[hash2];
|
||||
|
||||
denseArray[sparseArray[hash2]] = tempElement;
|
||||
denseIndexArray[sparseArray[hash2]] = tempIndex;
|
||||
sparseArray[hash2] = tempSparse;
|
||||
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Swaps two elements in the dense array.
|
||||
* This only swaps their position in the dense array and updates their
|
||||
* Sparse index reference in the sprase array accordingly.
|
||||
* This swaps using a index(position in the dense array) and a hash (EntityID)
|
||||
* This DOES NOT change the hash of the elements.
|
||||
* \param index1
|
||||
* The position in the dense array of the first element
|
||||
* \param hash
|
||||
* Hash of the second element
|
||||
***************************************************************************/
|
||||
virtual void SwapIndexHash(EntityIndex index1, EntityIndex hash) noexcept
|
||||
{
|
||||
if (index1 >= denseArray.size() || !Has(hash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Swap(denseIndexArray[index1], hash);
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Adds a new element to the SparseSet.
|
||||
* \param hash
|
||||
* The hash of the new element.
|
||||
* Nothing is added if the SparseSet already contains an element with
|
||||
* the same hash.
|
||||
* \param element
|
||||
* A reference to the element to be added. This will be passed in as a
|
||||
* copy and the default copy constructor will be used to copy the element
|
||||
* into the dense array.
|
||||
***************************************************************************/
|
||||
void Add(EntityIndex hash, T& element) noexcept
|
||||
{
|
||||
if (!IsValid(hash) || Has(hash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
denseArray.emplace_back(element);
|
||||
denseIndexArray.emplace_back (hash);
|
||||
sparseArray[hash] = EntityIndex(denseIndexArray.size() - 1);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Adds a new element to the SparseSet.
|
||||
* \param hash
|
||||
* The hash of the new element.
|
||||
* Nothing is added if the SparseSet already contains an element with
|
||||
* the same hash.
|
||||
* \return
|
||||
* None
|
||||
***************************************************************************/
|
||||
void Add(EntityIndex hash) noexcept
|
||||
{
|
||||
if (!IsValid(hash) || Has(hash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
denseArray.emplace_back(T());
|
||||
denseIndexArray.emplace_back(hash);
|
||||
sparseArray[hash] = EntityIndex(denseIndexArray.size() - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Removes an element from the Sparse Set
|
||||
* \param hash
|
||||
*
|
||||
***************************************************************************/
|
||||
virtual void Remove(EntityIndex hash) noexcept
|
||||
{
|
||||
if (!Has(hash))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Get the index of the item to be removed.
|
||||
EntityIndex index = sparseArray[hash];
|
||||
|
||||
//Get the sparse index of the last element in the dense array.
|
||||
EntityIndex lastSparse = denseIndexArray.back();
|
||||
|
||||
//Copy the contents of the last elements to the replace the element we are trying to remove
|
||||
//denseArray[index] = denseArray.back();
|
||||
//denseIndexArray[index] = denseIndexArray.back();
|
||||
|
||||
//denseArray.erase(denseArray.begin() + index);
|
||||
//denseIndexArray.erase(denseIndexArray.begin() + index);
|
||||
Swap(hash, lastSparse);
|
||||
|
||||
//update the sparse array with the new index of our last element.
|
||||
sparseArray[lastSparse] = index;
|
||||
sparseArray[hash] = UINT16_MAX;
|
||||
|
||||
//Pop out the last element since we no longer need it
|
||||
denseArray.pop_back();
|
||||
denseIndexArray.pop_back();
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the element specified by a hash. This will be casted to a void
|
||||
* pointer
|
||||
* \param hash
|
||||
* The Index of the element.
|
||||
* \return
|
||||
* A void pointer to the element.
|
||||
***************************************************************************/
|
||||
virtual void* Get(EntityIndex hash) noexcept
|
||||
{
|
||||
if (!Has(hash))
|
||||
{
|
||||
//no such element in this sparse set.
|
||||
return nullptr;
|
||||
}
|
||||
return (void*) &denseArray[sparseArray[hash]];
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,248 @@
|
|||
/*********************************************************************
|
||||
* \file SHSparseSetContainer.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for SHSparseSetContainer template class.
|
||||
* This is a container for SHSparseSets meant to contain SparseSets of
|
||||
* different types that are derived from a shared Base class.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SH_SPARSE_SET_CONTAINER_H
|
||||
#define SH_SPARSE_SET_CONTAINER_H
|
||||
|
||||
#include "SHSparseSet.h"
|
||||
#include "SHFamily.h"
|
||||
#include "../Components/SHComponent.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
template<typename Base>
|
||||
class SHSparseSetContainer
|
||||
{
|
||||
private:
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//The container of SparseSets.
|
||||
std::vector<SHSparseBase*> container;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Default constructor for the SHSparseSetContainer class
|
||||
***************************************************************************/
|
||||
SHSparseSetContainer() = default;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Default destructor for the SHSparseSetContainer class.
|
||||
***************************************************************************/
|
||||
~SHSparseSetContainer()
|
||||
{
|
||||
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||
{
|
||||
delete (*it);
|
||||
}
|
||||
};
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Attempts to create a SparseSet for the specified derived class.
|
||||
* If a SparseSet of the same class type has already been created,
|
||||
* nothing is re-created.
|
||||
* @tparam Derived
|
||||
* The type of the SparseSet to create.
|
||||
***************************************************************************/
|
||||
template<typename Derived>
|
||||
ENABLE_IF_DERIVED(void, Base, Derived) CreateSparseSet() noexcept
|
||||
{
|
||||
EntityID typeID = SHFamilyID<Base>::template GetID<Derived>();
|
||||
|
||||
if (container.size() > typeID)
|
||||
{
|
||||
if (container[typeID] == nullptr)
|
||||
{
|
||||
container[typeID] = (SHSparseBase*)new SHSparseSet<Derived, MAX_EID>();
|
||||
}
|
||||
return;
|
||||
}
|
||||
while (container.size() <= typeID)
|
||||
{
|
||||
container.push_back(nullptr);
|
||||
}
|
||||
container[typeID] = (SHSparseBase*)new SHSparseSet<Derived,MAX_EID>();
|
||||
}
|
||||
|
||||
//Cant use ENABLE_IF_DERIVED here because the macro is defined before template is defined.
|
||||
//Hence the return type that is a templated class will be an issue.
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the sparse set specified by a type. This converts the type to
|
||||
* a type ID using SHFamilyID and use that as the index.
|
||||
* This will attempt to Create a sparse set if it doesn't exist.
|
||||
* \return
|
||||
* The base class pointer to the sparse set.
|
||||
***************************************************************************/
|
||||
template<typename Derived>
|
||||
std::enable_if_t< std::is_base_of_v<Base,Derived>,SHSparseSet<Derived,MAX_EID>* > GetSparseSet() noexcept
|
||||
{
|
||||
EntityID typeID = SHFamilyID<Base>::template GetID<Derived>();
|
||||
if (container.size() <= typeID || container[typeID] == nullptr)
|
||||
{
|
||||
CreateSparseSet<Derived>();
|
||||
}
|
||||
|
||||
return (SHSparseSet<Derived, MAX_EID>*)container[typeID];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the sparse set at the specified index.
|
||||
* \param typeID
|
||||
* The index of the sparse set to get.
|
||||
* \return
|
||||
* The base class pointer to the sparse set.
|
||||
***************************************************************************/
|
||||
SHSparseBase* GetSparseSet_ID(uint32_t typeID) noexcept
|
||||
{
|
||||
//assert(typeID >= container.size());
|
||||
|
||||
return container[typeID];
|
||||
}
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Get the number of elements in the specified SparseSet
|
||||
* @tparam Derived
|
||||
* The type of the SparseSet
|
||||
***************************************************************************/
|
||||
template<typename Derived>
|
||||
inline ENABLE_IF_DERIVED(EntityID, Base, Derived)Count() noexcept
|
||||
{
|
||||
return GetSparseSet<Derived>()->Count();
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Get the dense array of the specified SparseSet
|
||||
* @tparam Derived
|
||||
* The type of the SparseSet
|
||||
* \return
|
||||
* Returns a reference to the dense array of the specified SparseSet
|
||||
***************************************************************************/
|
||||
template<typename Derived>
|
||||
inline std::enable_if_t < std::is_base_of_v<Base, Derived>, std::vector<Derived>& > GetDense() noexcept
|
||||
{
|
||||
return GetSparseSet<Derived>()->GetDense();
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Remove all elements with the specified hash from all the SparseSets in
|
||||
* the container.
|
||||
* \param hash
|
||||
* The hash of the elements to remove.
|
||||
***************************************************************************/
|
||||
void RemoveElements(EntityIndex hash) noexcept
|
||||
{
|
||||
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||
{
|
||||
|
||||
if (*it)
|
||||
{
|
||||
(*it)->Remove(hash);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Clear all SparseSets in the container.
|
||||
***************************************************************************/
|
||||
void ClearAllElements() noexcept
|
||||
{
|
||||
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||
{
|
||||
(*it)->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Sets the isActive variable in the elements with the specified hash
|
||||
* in all the SparseSets in the container.
|
||||
* This assuumes that the element types has a isActive boolean.
|
||||
* \param hash
|
||||
* hash of the elements
|
||||
* \param active
|
||||
* The active state to set to.
|
||||
***************************************************************************/
|
||||
void SetElementActive(EntityIndex hash, bool active) noexcept
|
||||
{
|
||||
(void)active;
|
||||
for (std::vector<SHSparseBase*>::iterator it = container.begin(); it != container.end(); ++it)
|
||||
{
|
||||
|
||||
if (*it)
|
||||
{
|
||||
SHComponent* comp = static_cast<SHComponent*>((*it)->Get(hash));
|
||||
if (comp)
|
||||
{
|
||||
comp->isActive = active;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the element of a specified hash from the Sparse set of indicated index.
|
||||
* \param typeIndex
|
||||
* The index of the sparse set which we are trying to get from
|
||||
* \param hash
|
||||
* The hash that the element belongs to.
|
||||
* \return
|
||||
* The address of the element casted to a void*
|
||||
***************************************************************************/
|
||||
void* GetElement(uint32_t typeIndex, EntityIndex hash) noexcept
|
||||
{
|
||||
if (typeIndex >= container.size())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return container[typeIndex]->Get(hash);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the size of the SparseSetContainer.
|
||||
* \return
|
||||
* The number of sparse sets in this container.
|
||||
***************************************************************************/
|
||||
|
||||
size_t Size() noexcept
|
||||
{
|
||||
return container.size();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef SH_MACROS_H
|
||||
#define SH_MACROS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
|
||||
typedef uint32_t EntityID;
|
||||
typedef uint16_t EntityIndex;
|
||||
typedef uint32_t ComponentTypeID;
|
||||
|
||||
|
||||
const EntityIndex MAX_EID = 51000;
|
||||
|
||||
|
||||
|
||||
#define ENABLE_IF_DERIVED(__RETURN__, __BASE__, __DERIVED__)\
|
||||
std::enable_if_t<std::is_base_of_v<__BASE__,__DERIVED__>,__RETURN__>
|
||||
|
||||
|
||||
#define ENABLE_IF_UINT(_TYPE, _RETURN)\
|
||||
typename std::enable_if<(std::is_integral<_TYPE>::value && !std::is_signed<_TYPE>::value),_RETURN>::type
|
||||
|
||||
#endif
|
|
@ -0,0 +1,102 @@
|
|||
/*********************************************************************
|
||||
* \file SHComponentManager.cpp
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Definition of functions for the SHComponentManager class.
|
||||
* This is the interface that the systems are going to use to interacte with
|
||||
* the components. The SparseSetContainer of components is stored and managed
|
||||
* here.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
#include "SHpch.h"
|
||||
#include "SHComponentManager.h"
|
||||
#include "SHEntityManager.h"
|
||||
#include "SHSystemManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
||||
SHSparseSetContainer<SHComponent> SHComponentManager::componentSet;
|
||||
std::vector<SHComponentGroup> SHComponentManager::componentGroups;
|
||||
|
||||
void SHComponentManager::Exit() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void SHComponentManager::RemoveComponentsOfEntity(EntityID entityID) noexcept
|
||||
{
|
||||
|
||||
if (!SHEntityManager::IsValidEID(entityID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < componentSet.Size(); ++i)
|
||||
{
|
||||
SHComponent* comp = (SHComponent*) componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entityID));
|
||||
if (comp)
|
||||
{
|
||||
comp->OnDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (auto & grp : componentGroups)
|
||||
{
|
||||
grp.RemoveEntity(entityID);
|
||||
}
|
||||
|
||||
componentSet.RemoveElements(EntityHandleGenerator::GetIndex(entityID));
|
||||
|
||||
//entityHandle.RemoveHandle(entityID);
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool SHComponentManager::HasComponent_ID(EntityID entityID, uint32_t componentTypeID) noexcept
|
||||
{
|
||||
return componentSet.GetSparseSet_ID(componentTypeID)->Has(EntityHandleGenerator::GetIndex(entityID));
|
||||
}
|
||||
|
||||
|
||||
void SHComponentManager::SetActive(EntityID entityID, bool active) noexcept
|
||||
{
|
||||
componentSet.SetElementActive(EntityHandleGenerator::GetIndex(entityID), active);
|
||||
}
|
||||
|
||||
void SHComponentManager::SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, uint32_t componentTypeID) noexcept
|
||||
{
|
||||
componentSet.GetSparseSet_ID(componentTypeID)->SwapIndexHash(index, EntityHandleGenerator::GetIndex(hash));
|
||||
}
|
||||
|
||||
void SHComponentManager::ChangeParent(EntityID entity, EntityID newParent)
|
||||
{
|
||||
for (uint32_t i = 0; i < (uint32_t)componentSet.Size(); ++i)
|
||||
{
|
||||
SHComponent* component = (SHComponent*)componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entity));
|
||||
if (component == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
component->ChangeParent(newParent);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SHComponentManager::ChangeParent(EntityID entity)
|
||||
{
|
||||
for (uint32_t i = 0; i < (uint32_t)componentSet.Size(); ++i)
|
||||
{
|
||||
SHComponent* component = (SHComponent*)componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entity));
|
||||
if (component == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
component->ChangeParent();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,477 @@
|
|||
/*********************************************************************
|
||||
* \file SHComponentManager.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the SHComponentManager class.
|
||||
* This is the interface that the systems are going to use to interacte with
|
||||
* the components.
|
||||
* The SparseSetContainer of components is stored and managed
|
||||
* here.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SH_ENGINE_H
|
||||
#define SH_ENGINE_H
|
||||
|
||||
#include "../General/SHSparseSetContainer.h"
|
||||
#include "../Components/SHComponent.h"
|
||||
#include "../Components/SHComponentGroup.h"
|
||||
//#include "Scene/SHSceneNode.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHComponentManager
|
||||
{
|
||||
private:
|
||||
|
||||
//The SparseSetContainer of components.
|
||||
static SHSparseSetContainer<SHComponent> componentSet;
|
||||
//The Container of all Componentgroups
|
||||
static std::vector<SHComponentGroup> componentGroups;
|
||||
|
||||
friend class SHSceneNode;
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* This is called by the SHSceneNode friend class to change the parent
|
||||
* of an entity.
|
||||
* This function is privated as it is not for general use.
|
||||
* \param entity
|
||||
* The entityID of the entity which to change the parent of.
|
||||
* \param newParent
|
||||
* The entityID of the new parent.
|
||||
***************************************************************************/
|
||||
static void ChangeParent(EntityID entity, EntityID newParent);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Overloaded function of Change parent to change the parent of an entity to
|
||||
* the root node.
|
||||
* This is called by the SHSceneNode friend class to change the parent
|
||||
* of an entity.
|
||||
* This function is privated as it is not for general use.
|
||||
* \param entity
|
||||
* The entityID of the entity which to change the parent of.
|
||||
***************************************************************************/
|
||||
static void ChangeParent(EntityID entity);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
/*!*************************************************************************
|
||||
* This class is used as a static class.
|
||||
* No objects of this type should be created
|
||||
***************************************************************************/
|
||||
SHComponentManager() = delete;
|
||||
~SHComponentManager() = delete;
|
||||
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Cleans up the memory used in the Engine.
|
||||
***************************************************************************/
|
||||
static void Exit() noexcept;
|
||||
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Creates the SparseSet for the specified Component type
|
||||
* @tparam T
|
||||
* Component Type to create.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static void CreateComponentSparseSet() noexcept
|
||||
{
|
||||
componentSet.CreateSparseSet<T>();
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Getter for the dense array of a specified Component Type.
|
||||
* @tparam T
|
||||
* Component Type
|
||||
* \return std::vector<T>&
|
||||
* reference to the dense array from the SparseSet of the Component Type T.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static std::vector<T>& GetDense() noexcept
|
||||
{
|
||||
return componentSet.GetDense<T>();
|
||||
}
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Gets the Component of the entity with the specified entityID
|
||||
*
|
||||
* This is the safe version of GetComponent_s which does a HasComponent to make
|
||||
* sure that the entity has such a component and returns nullptr if it doesn't
|
||||
*
|
||||
* This safe version also checks if the sparse set of this component type
|
||||
* has been created in SHComponentManager and creates one if it doesn't
|
||||
*
|
||||
* @tparam T
|
||||
* Type of Component to get.
|
||||
* \param entityID
|
||||
* EntityID of the entity that we are trying to get the component of.
|
||||
* \return
|
||||
* A pointer to the component of the entity.
|
||||
* Returns nullptr if the entity does not contain such a component.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static ENABLE_IF_DERIVED(T*, SHComponent, T) GetComponent_s(EntityID entityID) noexcept
|
||||
{
|
||||
EntityID typeID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||
|
||||
if (componentSet.container.size() <= typeID)
|
||||
{
|
||||
componentSet.CreateSparseSet<T>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
return (componentSet.GetSparseSet<T>()->GetElement_s(EntityHandleGenerator::GetIndex(entityID)));
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Gets the Component of the entity with the specified entityID
|
||||
*
|
||||
* This is the faster unsafe version.
|
||||
* Use only when sure that the entity has such a Component type. This could
|
||||
* give garbage value or the component of a different entity if the entity
|
||||
* does not have the specified component type. This is usually used with
|
||||
* ComponentGroups
|
||||
*
|
||||
* This unsafe version bypass the HasComponent check.
|
||||
*
|
||||
* This unsafe version bypass the check for sparseSet creation.
|
||||
*
|
||||
* @tparam T
|
||||
* Type of Component to get.
|
||||
* \param entityID
|
||||
* EntityID of the entity that we are trying to get the component of.
|
||||
* \return
|
||||
* A pointer to the component of the entity.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static ENABLE_IF_DERIVED(T*,SHComponent, T) GetComponent(EntityID entityID) noexcept
|
||||
{
|
||||
//EntityID typeID = SHFamilyID<SHComponent>::template GetID<T>();
|
||||
|
||||
return (componentSet.GetSparseSet<T>()->GetElement(EntityHandleGenerator::GetIndex(entityID)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Add a component to the specified entityID
|
||||
* Nothing is added if the entityID already have a component of the same type.
|
||||
* @tparam T
|
||||
* Type of Component to be added.
|
||||
* @tparam Args
|
||||
* The args types to pass to the constructor of the Component
|
||||
* \param entityID
|
||||
* EntityID to add this component to.
|
||||
* \param args
|
||||
* The args to pass to the constructor of the Component
|
||||
* \return
|
||||
* None.
|
||||
***************************************************************************/
|
||||
template<typename T >
|
||||
static ENABLE_IF_DERIVED(void,SHComponent,T) AddComponent(EntityID entityID) noexcept
|
||||
{
|
||||
T element{};
|
||||
|
||||
componentSet.GetSparseSet_ID(SHFamilyID<SHComponent>::GetID<T>())->Add(EntityHandleGenerator::GetIndex(entityID));
|
||||
|
||||
|
||||
SHComponent* comp = (SHComponent*)componentSet.GetElement(SHFamilyID<SHComponent>::GetID<T>(), EntityHandleGenerator::GetIndex(entityID));
|
||||
comp->entityID = entityID;
|
||||
|
||||
for (auto& grp : componentGroups)
|
||||
{
|
||||
grp.AddComponentCheck(entityID, SHFamilyID<SHComponent>::GetID<T>());
|
||||
}
|
||||
|
||||
|
||||
if (comp)
|
||||
{
|
||||
comp->OnCreate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Add Component using a component type ID. This assumes that the sparse
|
||||
* set is already created for the component type ID.
|
||||
* \param entityID
|
||||
* The entity ID of the entity
|
||||
* \param componentTypeID
|
||||
* The Type ID of the Component Type.
|
||||
* \return
|
||||
* none
|
||||
***************************************************************************/
|
||||
static void AddComponent(EntityID entityID, uint32_t componentTypeID) noexcept
|
||||
{
|
||||
componentSet.GetSparseSet_ID(componentTypeID)->Add(EntityHandleGenerator::GetIndex(entityID));
|
||||
|
||||
|
||||
SHComponent* comp = (SHComponent*)componentSet.GetElement(componentTypeID, EntityHandleGenerator::GetIndex(entityID));
|
||||
comp->entityID = entityID;
|
||||
|
||||
for (auto& grp : componentGroups)
|
||||
{
|
||||
grp.AddComponentCheck(entityID,componentTypeID);
|
||||
}
|
||||
|
||||
|
||||
if (comp)
|
||||
{
|
||||
comp->OnCreate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Checks if the specified entityID has a component of specified type.
|
||||
* @tparam T
|
||||
* Type of Component to check for.
|
||||
* \param entityID
|
||||
* EntityID to check for.
|
||||
* \return bool
|
||||
* True if the entity has a component of specified type.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static ENABLE_IF_DERIVED(bool, SHComponent, T) HasComponent(EntityID entityID) noexcept
|
||||
{
|
||||
return componentSet.GetSparseSet<T>()->Has(EntityHandleGenerator::GetIndex(entityID));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Checks if the specified entityID has a component of specified type.
|
||||
* The component type is specified by a component type ID
|
||||
* @tparam T
|
||||
* Type of Component to check for.
|
||||
* \param entityID
|
||||
* EntityID to check for.
|
||||
* \param componentTypeID
|
||||
* The component type ID to look for
|
||||
* \return bool
|
||||
* True if the entity has a component of specified type.
|
||||
***************************************************************************/
|
||||
static bool HasComponent_ID(EntityID entityID, uint32_t componentTypeID) noexcept;
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Remove the Component of specified type from the entity.
|
||||
* @tparam T
|
||||
* Component type to be removed
|
||||
* \param entityID
|
||||
* EntityID of the object to remove the component from.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static ENABLE_IF_DERIVED(void, SHComponent, T) RemoveComponent(EntityID entityID) noexcept
|
||||
{
|
||||
if (!HasComponent<T>(entityID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SHComponent* comp = (SHComponent*)componentSet.GetElement(SHFamilyID<SHComponent>::GetID<T>(), EntityHandleGenerator::GetIndex(entityID));
|
||||
if (comp)
|
||||
{
|
||||
comp->OnDestroy();
|
||||
}
|
||||
|
||||
for (auto& grp : componentGroups)
|
||||
{
|
||||
grp.RemoveComponentCheck<T>(entityID);
|
||||
}
|
||||
|
||||
|
||||
componentSet.GetSparseSet<T>()->Remove(EntityHandleGenerator::GetIndex(entityID));
|
||||
}
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Swaps to positioning of two components in their dense array.
|
||||
* This does not swap the entity that the components belong to
|
||||
* @tparam T
|
||||
* Type of the Component to swap.
|
||||
* \param entityID1
|
||||
* entityID of the first entity.
|
||||
* \param entityID2
|
||||
* entityID of the second entity.
|
||||
* \return
|
||||
* None.
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static ENABLE_IF_DERIVED(void, SHComponent, T) SwapInDense(EntityID entityID1, EntityID entityID2) noexcept
|
||||
{
|
||||
componentSet.GetSparseSet<T>()->Swap(EntityHandleGenerator::GetIndex(entityID1), EntityHandleGenerator::GetIndex(entityID2));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Swaps to positioning of two components in their dense array.
|
||||
* This does not swap the entity that the components belong to.
|
||||
* This is the overloaded function that takes 2 Entity Index
|
||||
* \param index
|
||||
* The entity Index of the first entity.
|
||||
* \param hash
|
||||
* The entity Index of the second entity.
|
||||
* \return
|
||||
* none
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static ENABLE_IF_DERIVED(void, SHComponent, T) SwapInDenseByIndex(EntityIndex index, EntityIndex hash) noexcept
|
||||
{
|
||||
componentSet.GetSparseSet<T>()->SwapIndexHash(index, EntityHandleGenerator::GetIndex(hash));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Swaps to positioning of two components in their dense array.
|
||||
* This does not swap the entity that the components belong to.
|
||||
* This swap using a component type ID
|
||||
* \param index
|
||||
* The entity Index of the first entity
|
||||
* \param hash
|
||||
* The entity ID of the second entity
|
||||
* \param componentTypeID
|
||||
* The Type ID of the component type ID
|
||||
* \return
|
||||
*
|
||||
***************************************************************************/
|
||||
static void SwapInDenseByIndexHash_ID(EntityIndex index, EntityID hash, uint32_t componentTypeID) noexcept;
|
||||
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Removes and destroy all components tied to an entity.
|
||||
* entityID
|
||||
* \param entityID
|
||||
* entityID of the entity to be removed.
|
||||
***************************************************************************/
|
||||
static void RemoveComponentsOfEntity(EntityID entityID) noexcept;
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the number of components in a component sparse set.
|
||||
* \param componentTypeID
|
||||
* The type ID of the Component Type.
|
||||
* \return
|
||||
* The number of components in the component sparse set.
|
||||
***************************************************************************/
|
||||
static EntityIndex ComponentCount_ID(uint32_t componentTypeID)
|
||||
{
|
||||
return componentSet.GetSparseSet_ID(componentTypeID)->Count();
|
||||
}
|
||||
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Set the isActive boolean of all Components that the entity has
|
||||
* \param entityID
|
||||
* The entityID of the entity
|
||||
* \param active
|
||||
* The active state to set to
|
||||
***************************************************************************/
|
||||
static void SetActive(EntityID entityID, bool active) noexcept;
|
||||
|
||||
template<typename... T>
|
||||
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, T>), uint32_t> CreateComponentGroup(uint32_t numOwningComponents)
|
||||
{
|
||||
std::vector<uint32_t> templateIDs{ (SHFamilyID<SHComponent>::GetID<T>())... };
|
||||
|
||||
for (auto& g : componentGroups)
|
||||
{
|
||||
for (auto const& oID : g.ownedComponentTypes)
|
||||
{
|
||||
for (uint32_t i = 0; i < numOwningComponents; ++i)
|
||||
{
|
||||
if ((templateIDs[i] == oID))
|
||||
{
|
||||
assert("This Component is owned by another group");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SHComponentGroup grp;
|
||||
for (uint32_t i = 0; i < numOwningComponents; ++i)
|
||||
{
|
||||
grp.ownedComponentTypes.push_back(templateIDs[i]);
|
||||
}
|
||||
for (uint32_t i = 0; i < templateIDs.size(); ++i)
|
||||
{
|
||||
grp.componentTypeIDs.push_back(templateIDs[i]);
|
||||
}
|
||||
|
||||
if (grp.ownedComponentTypes.size() != grp.componentTypeIDs.size())
|
||||
{
|
||||
if (grp.ownedComponentTypes.empty())
|
||||
{
|
||||
grp.ownershipType = OWNERSHIP_TYPE::NON_OWNERSHIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
grp.ownershipType = OWNERSHIP_TYPE::PARTIAL_OWNERSHIP;
|
||||
}
|
||||
}
|
||||
|
||||
componentGroups.push_back(grp);
|
||||
return (uint32_t)componentGroups.size() - 1;
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get a reference to the component group.
|
||||
* \param index
|
||||
* The index of the component group
|
||||
* \return
|
||||
* A reference to the component group.
|
||||
***************************************************************************/
|
||||
static SHComponentGroup& GetComponentGroup(uint16_t index) noexcept
|
||||
{
|
||||
return componentGroups[index];
|
||||
}
|
||||
|
||||
static void AddScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept;
|
||||
|
||||
static void RemoveScriptComponent(EntityID eid, std::string const& scriptClassName) noexcept;
|
||||
|
||||
|
||||
};// end SHComponentManager
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,232 @@
|
|||
/*********************************************************************
|
||||
* \file SHEntityManager.cpp
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Implementation for the SHEntityManager class.
|
||||
* Entity Manager is the interface class where users of the engine
|
||||
* and its systems interact with entity data in the engine. This
|
||||
* includes Creation and Destruction of entities and getting Entity by
|
||||
* an ID. This manager also ensures that each entity have a unique
|
||||
* handle using SHHandleGenerator.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
#include "SHpch.h"
|
||||
#include "SHEntityManager.h"
|
||||
//#include "Scene/SHSceneGraph.h"
|
||||
//#include "Serialization/SHSerialization.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
std::vector<std::unique_ptr<SHEntity>> SHEntityManager::entityVec;
|
||||
EntityHandleGenerator SHEntityManager::entityHandle;
|
||||
|
||||
SHEntity* SHEntityManager::GetEntityByID(EntityID entityID) noexcept
|
||||
{
|
||||
if (!IsValidEID(entityID))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EntityIndex eIndex = entityHandle.GetIndex(entityID);
|
||||
return entityVec[eIndex].get();
|
||||
|
||||
}
|
||||
|
||||
bool SHEntityManager::IsValidEID(EntityID entityID) noexcept
|
||||
{
|
||||
if (!entityHandle.IsValid(entityID))
|
||||
return false;
|
||||
|
||||
EntityIndex eIndex = entityHandle.GetIndex(entityID);
|
||||
if (entityVec.size() <= eIndex || !entityVec[eIndex])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
EntityIndex SHEntityManager::GetEntityIndex(EntityID entityID) noexcept
|
||||
{
|
||||
return entityHandle.GetIndex(entityID);
|
||||
}
|
||||
|
||||
EntityID SHEntityManager::CreateEntity(std::vector<uint32_t>const& componentTypeIDs, std::string const& name,EntityID parentEID)
|
||||
{
|
||||
EntityID eID = entityHandle.GetNewHandle();
|
||||
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||
if (eIndex > entityVec.size())
|
||||
{
|
||||
assert("FATAL ERROR: EntityIndex out of range in Entity Creation");
|
||||
}
|
||||
else if (eIndex == entityVec.size())
|
||||
{
|
||||
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!entityVec[eIndex])
|
||||
{
|
||||
//There is still an entity stored there.Something went wrong
|
||||
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||
}
|
||||
|
||||
//Reset it to a newly constructed entity
|
||||
entityVec[eIndex].reset(new SHEntity());
|
||||
}
|
||||
|
||||
|
||||
entityVec[eIndex]->entityID = eID;
|
||||
entityVec[eIndex]->name = name;
|
||||
for (auto& id : componentTypeIDs)
|
||||
{
|
||||
SHComponentManager::AddComponent(eID, id);
|
||||
}
|
||||
|
||||
//(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
|
||||
/*if (entityHandle.IsValid(parentEID) == false)
|
||||
{
|
||||
entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
entityVec[eIndex]->SetParent(parentEID);
|
||||
}*/
|
||||
|
||||
|
||||
//TODO Link to Scene graph.
|
||||
|
||||
return eID;
|
||||
|
||||
}
|
||||
|
||||
EntityID SHEntityManager::CreateEntity(std::vector<uint32_t>const& componentTypeIDs, EntityID desiredEID, std::string const& name, EntityID parentEID)
|
||||
{
|
||||
EntityID eID ;
|
||||
|
||||
if (entityHandle.ClaimHandle(desiredEID) == true)
|
||||
eID = desiredEID;
|
||||
else
|
||||
eID = entityHandle.GetNewHandle();
|
||||
|
||||
|
||||
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||
if (eIndex > entityVec.size())
|
||||
{
|
||||
EntityIndex size = (EntityIndex)entityVec.size();
|
||||
for (EntityIndex i = 0; i <= eIndex - size; ++i)
|
||||
{
|
||||
entityVec.push_back(nullptr);
|
||||
|
||||
}
|
||||
entityVec[eIndex].reset(new SHEntity());
|
||||
}
|
||||
else if (eIndex == entityVec.size())
|
||||
{
|
||||
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!entityVec[eIndex])
|
||||
{
|
||||
//There is still an entity stored there.Something went wrong
|
||||
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||
}
|
||||
|
||||
//Reset it to a newly constructed entity
|
||||
entityVec[eIndex].reset(new SHEntity());
|
||||
}
|
||||
|
||||
|
||||
entityVec[eIndex]->entityID = eID;
|
||||
entityVec[eIndex]->name = name;
|
||||
for (auto& id : componentTypeIDs)
|
||||
{
|
||||
SHComponentManager::AddComponent(eID, id);
|
||||
}
|
||||
|
||||
//(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
|
||||
|
||||
//if (entityHandle.IsValid(parentEID) == false)
|
||||
//{
|
||||
// entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// entityVec[eIndex]->SetParent(parentEID);
|
||||
//}
|
||||
|
||||
//TODO Link to scene graph.
|
||||
|
||||
|
||||
return eID;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SHEntityManager::DestroyEntity(EntityID eID) noexcept
|
||||
{
|
||||
if (!IsValidEID(eID))
|
||||
{
|
||||
//Entity does not exist or already destroyed.
|
||||
return;
|
||||
}
|
||||
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||
|
||||
//Call all the children to Destroy themselves first before the parent is destroyed.
|
||||
if (entityVec[eIndex])
|
||||
{
|
||||
//auto& children = entityVec[eIndex]->GetChildrenID();
|
||||
//while(!children.empty())
|
||||
//{
|
||||
// DestroyEntity(children[0]);
|
||||
//}
|
||||
|
||||
//SHSceneNode* parentNode = entityVec[eIndex]->GetSceneNode()->GetParent();
|
||||
|
||||
//SHSceneGraph::RemoveChild(parentNode,entityVec[eIndex].get());
|
||||
|
||||
//TODO remove from parent and recursively delete child.
|
||||
|
||||
|
||||
|
||||
SHComponentManager::RemoveComponentsOfEntity(eID);
|
||||
|
||||
entityHandle.RemoveHandle(eID);
|
||||
|
||||
entityVec[eIndex].reset(nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SHEntityManager::DestroyAllEntity() noexcept
|
||||
{
|
||||
for (auto& entity : entityVec)
|
||||
{
|
||||
|
||||
if (entity)
|
||||
{
|
||||
DestroyEntity(entity->GetEID());
|
||||
}
|
||||
}
|
||||
entityHandle.ClearAllHandles();
|
||||
}
|
||||
|
||||
EntityIndex SHEntityManager::GetEntityCount() noexcept
|
||||
{
|
||||
return entityHandle.GetActiveHandleCount();
|
||||
}
|
||||
|
||||
|
||||
/*EntityID SHEntityManager::DuplicateEntity(EntityID eid) noexcept
|
||||
{
|
||||
if (entityHandle.IsValid(eid) == false)
|
||||
return MAX_EID;
|
||||
|
||||
std::string data = SHSerialization::SerializeEntityToString(eid);
|
||||
return SHSerialization::DeserializeEntityToSceneFromString(data);
|
||||
}*/
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
/*********************************************************************
|
||||
* \file SHEntityManger.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Definition for the SHEntityManager class.
|
||||
* Entity Manager is the interface class where users of the engine
|
||||
* and its systems interact with entity data in the engine. This
|
||||
* includes Creation and Destruction of entities and getting Entity by
|
||||
* an ID. This manager also ensures that each entity have a unique
|
||||
* handle using SHHandleGenerator.
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SH_ENTITY_MANAGER_H
|
||||
#define SH_ENTITY_MANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "../Entity/SHEntity.h"
|
||||
#include "../Components/SHComponent.h"
|
||||
#include "../General/SHHandleGenerator.h"
|
||||
#include "../SHECSMacros.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
||||
class SHEntityManager
|
||||
{
|
||||
private:
|
||||
static std::vector<std::unique_ptr<SHEntity>> entityVec;
|
||||
//The handle generator to generate entityIDs.
|
||||
static EntityHandleGenerator entityHandle;
|
||||
|
||||
public:
|
||||
SHEntityManager() = delete;
|
||||
~SHEntityManager() = delete;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get a pointer to the entity using the entityID.
|
||||
* \param entityID
|
||||
* The entity ID of the entity
|
||||
* \return
|
||||
* A pointer to the entity.
|
||||
* A nullptr is returned if there is no such entity or if it is destroyed.
|
||||
***************************************************************************/
|
||||
static SHEntity* GetEntityByID(EntityID entityID) noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Checks if the current Entity ID is in use and alive.
|
||||
* \param entityID
|
||||
* The entity ID of the entity
|
||||
* \return
|
||||
* true if the entity ID is in use and alive.
|
||||
***************************************************************************/
|
||||
static bool IsValidEID(EntityID entityID) noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the index portion of the Entity ID.
|
||||
* \param entityID
|
||||
* The entity ID of the entity
|
||||
* \return
|
||||
* The index of the entity
|
||||
***************************************************************************/
|
||||
static EntityIndex GetEntityIndex(EntityID entityID) noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Template function to Create a new Entity with Components specified
|
||||
* by the template arguements.
|
||||
* \param name
|
||||
* Name of the entity (This is not unique)
|
||||
* \param parentEID
|
||||
* The entity ID of the parent. This does not call UpdateHierarchy hence
|
||||
* the parent of the entity is not updated until UpdateHierarchy is called.
|
||||
* \return
|
||||
* EntityID of the new Entity
|
||||
***************************************************************************/
|
||||
template<typename ...ComponentTypes>
|
||||
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), EntityID> CreateEntity(std::string const& name = "Default", EntityID parentEID = MAX_EID)
|
||||
{
|
||||
EntityID eID = entityHandle.GetNewHandle();
|
||||
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||
if (eIndex > entityVec.size())
|
||||
{
|
||||
assert("FATAL ERROR: EntityIndex out of range in Entity Creation");
|
||||
}
|
||||
else if (eIndex == entityVec.size())
|
||||
{
|
||||
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!entityVec[eIndex])
|
||||
{
|
||||
//There is still an entity stored there.Something went wrong
|
||||
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||
}
|
||||
|
||||
//Reset it to a newly constructed entity
|
||||
entityVec[eIndex].reset(new SHEntity());
|
||||
}
|
||||
entityVec[eIndex]->entityID = eID;
|
||||
entityVec[eIndex]->name = name;
|
||||
(SHComponentManager::AddComponent<ComponentTypes>(eID),...);
|
||||
|
||||
/*if (entityHandle.IsValid(parentEID) == false)
|
||||
{
|
||||
entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
entityVec[eIndex]->SetParent(parentEID);
|
||||
}*/
|
||||
|
||||
//TODO Link up with Scene graph
|
||||
|
||||
return eID;
|
||||
}
|
||||
|
||||
template<typename ...ComponentTypes>
|
||||
static std::enable_if_t<(... && std::is_base_of_v<SHComponent, ComponentTypes>), EntityID> CreateEntity(EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID)
|
||||
{
|
||||
EntityID eID;
|
||||
if (entityHandle.ClaimHandle(desiredEID) == true)
|
||||
eID = desiredEID;
|
||||
else
|
||||
eID = entityHandle.GetNewHandle();
|
||||
EntityIndex eIndex = entityHandle.GetIndex(eID);
|
||||
if (eIndex > entityVec.size())
|
||||
{
|
||||
EntityIndex size = (EntityIndex)entityVec.size();
|
||||
for (EntityIndex i = 0; i <= eIndex - size; ++i)
|
||||
{
|
||||
entityVec.push_back(nullptr);
|
||||
|
||||
}
|
||||
entityVec[eIndex].reset(new SHEntity());
|
||||
}
|
||||
else if (eIndex == entityVec.size())
|
||||
{
|
||||
entityVec.emplace_back(std::make_unique<SHEntity>());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!entityVec[eIndex])
|
||||
{
|
||||
//There is still an entity stored there.Something went wrong
|
||||
assert("FATAL ERROR: Entity Creation error. Entity Index Conflict");
|
||||
}
|
||||
|
||||
//Reset it to a newly constructed entity
|
||||
entityVec[eIndex].reset(new SHEntity());
|
||||
}
|
||||
entityVec[eIndex]->entityID = eID;
|
||||
entityVec[eIndex]->name = name;
|
||||
(SHComponentManager::AddComponent<ComponentTypes>(eID), ...);
|
||||
|
||||
/*if (entityHandle.IsValid(parentEID) == false)
|
||||
{
|
||||
entityVec[eIndex]->sceneNode.ConnectToRoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
entityVec[eIndex]->SetParent(parentEID);
|
||||
}*/
|
||||
|
||||
|
||||
//Link up with scene graph.
|
||||
|
||||
|
||||
return eID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Create Entity using a vector of ComponentTypeIDs.
|
||||
* \param componentTypeIDs
|
||||
* Vector of ComponentTypeIDs. This assumes that CreateSparseSet is called
|
||||
* for these ComponentTypes.
|
||||
* \param name
|
||||
* Name of the Entity (this is not unique)
|
||||
* \param parentEID
|
||||
* The entity ID of the parent. This does not call UpdateHierarchy hence
|
||||
* the parent of the entity is not updated until UpdateHierarchy is called.
|
||||
* \return
|
||||
* EntityID of the new Entity
|
||||
***************************************************************************/
|
||||
static EntityID CreateEntity(std::vector<ComponentTypeID>const& componentTypeIDs,std::string const& name = "Default", EntityID parentEID = MAX_EID);
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Create Entity using a vector of ComponentTypeIDs.
|
||||
* \param componentTypeIDs
|
||||
* Vector of ComponentTypeIDs. This assumes that CreateSparseSet is called
|
||||
* for these ComponentTypes.
|
||||
* \param name
|
||||
* Name of the Entity (this is not unique)
|
||||
* \param parentEID
|
||||
* The entity ID of the parent. This does not call UpdateHierarchy hence
|
||||
* the parent of the entity is not updated until UpdateHierarchy is called.
|
||||
* \return
|
||||
* EntityID of the new Entity
|
||||
***************************************************************************/
|
||||
static EntityID CreateEntity(std::vector<ComponentTypeID>const& componentTypeIDs, EntityID desiredEID, std::string const& name = "Default", EntityID parentEID = MAX_EID);
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Destroy the entity and all components tied to this entity.
|
||||
* This calls Destroy Entity for all of its children as well.
|
||||
* \param eID
|
||||
* The entity ID of the entity
|
||||
* \return
|
||||
* none
|
||||
***************************************************************************/
|
||||
static void DestroyEntity(EntityID eID) noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Destroy all Entities.
|
||||
* \return
|
||||
* none
|
||||
***************************************************************************/
|
||||
static void DestroyAllEntity() noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get the current number of entities.
|
||||
* \return
|
||||
* Number of entities.
|
||||
***************************************************************************/
|
||||
static EntityIndex GetEntityCount() noexcept;
|
||||
|
||||
//static EntityID DuplicateEntity(EntityID eid) noexcept;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
/*********************************************************************
|
||||
* \file SHSystem.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the SHSytem abstract base class
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SH_SYSTEM_H
|
||||
#define SH_SYSTEM_H
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHSystem
|
||||
{
|
||||
protected:
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Protected default constructor for SHSytem class
|
||||
***************************************************************************/
|
||||
SHSystem()= default;
|
||||
|
||||
public:
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Destructor for SHSytem class
|
||||
***************************************************************************/
|
||||
virtual ~SHSystem() = default;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Pure virtual Init function. Derived class must implement this
|
||||
***************************************************************************/
|
||||
virtual void Init() = 0;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Pure virtual Run function. Derived class must implement this
|
||||
* \param dt
|
||||
* Delta time
|
||||
***************************************************************************/
|
||||
virtual void Run(float dt) = 0;
|
||||
|
||||
/*!*************************************************************************
|
||||
* \brief
|
||||
* Pure virtual Exit function. Derived class must implement this
|
||||
***************************************************************************/
|
||||
virtual void Exit() = 0;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,57 @@
|
|||
/*********************************************************************
|
||||
* \file SHSystemManager.cpp
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Implementation for the SHSystemManager class.
|
||||
* SHSystemManager is the interface class where users of the engine create
|
||||
* the systems that gives the components their functionality. This also
|
||||
* ensures that the Init and Exit functions are ran at the appropriate time
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
#include "SHpch.h"
|
||||
#include "SHSystemManager.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
SHSystemManager::SystemContainer SHSystemManager::systemContainer;
|
||||
|
||||
|
||||
SHSystem* SHSystemManager::GetSystem(std::string name)
|
||||
{
|
||||
if (systemContainer.find(name) == systemContainer.end())
|
||||
{
|
||||
assert("Get System Error: No system with such name exist.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return systemContainer.find(name)->second.get();
|
||||
}
|
||||
|
||||
void SHSystemManager::Init() noexcept
|
||||
{
|
||||
for (auto& system : systemContainer)
|
||||
{
|
||||
system.second->Init();
|
||||
#ifdef _DEBUG
|
||||
std::cout << system.first << " Init" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void SHSystemManager::Exit() noexcept
|
||||
{
|
||||
for (auto& system : systemContainer)
|
||||
{
|
||||
system.second->Exit();
|
||||
//delete system.second;
|
||||
}
|
||||
|
||||
systemContainer.clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*********************************************************************
|
||||
* \file SHSystemManager.h
|
||||
* \author Daniel Chua Yee Chen
|
||||
* \brief Declaration for the SHSystemManager class.
|
||||
* SHSystemManager is the interface class where users of the engine create
|
||||
* the systems that gives the components their functionality. This also ensures that the Init and Exit functions are ran at the appropriate time
|
||||
*
|
||||
* \copyright Copyright (c) 2021 DigiPen Institute of Technology. Reproduction
|
||||
or disclosure of this file or its contents without the prior written
|
||||
consent of DigiPen Institute of Technology is prohibited.
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
#ifndef SH_SYSTEM_MANAGER_H
|
||||
#define SH_SYSTEM_MANAGER_H
|
||||
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include "../System/SHSystem.h"
|
||||
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
||||
class SHSystemManager
|
||||
{
|
||||
//type definition for the container we use to store our system
|
||||
using SystemContainer = std::unordered_map<std::string, std::unique_ptr<SHSystem>>;
|
||||
|
||||
private:
|
||||
static SystemContainer systemContainer;
|
||||
|
||||
|
||||
public:
|
||||
/*!*************************************************************************
|
||||
* This class is used as a static class.
|
||||
* No objects of this type should be created
|
||||
***************************************************************************/
|
||||
SHSystemManager() = delete;
|
||||
~SHSystemManager() = delete;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Create a system of type T and map it to a name.
|
||||
* throws an error if a system with the same name already exists.
|
||||
* \param name
|
||||
* name of the system
|
||||
* \return
|
||||
* none
|
||||
***************************************************************************/
|
||||
template<typename T>
|
||||
static std::enable_if_t<std::is_base_of_v<SHSystem, T>, void> CreateSystem(std::string const& name)
|
||||
{
|
||||
if (systemContainer.find(name) != systemContainer.end())
|
||||
{
|
||||
assert("System Creation Error: System with the same name already exist.");
|
||||
}
|
||||
|
||||
systemContainer.emplace(name, std::make_unique<T>());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Get a pointer to the System with a specified name.
|
||||
* \param name
|
||||
* Name of the system in the map
|
||||
* \return
|
||||
* Base System pointer.
|
||||
***************************************************************************/
|
||||
static SHSystem* GetSystem(std::string name);
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Call the Init function of all systems.
|
||||
* \return
|
||||
* none
|
||||
***************************************************************************/
|
||||
static void Init() noexcept;
|
||||
|
||||
/**************************************************************************
|
||||
* \brief
|
||||
* Call the Exit function of all systems.
|
||||
* \return
|
||||
***************************************************************************/
|
||||
static void Exit() noexcept;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue