diff --git a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp index 2683a6e9..3ef138ac 100644 --- a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp +++ b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp @@ -47,32 +47,57 @@ namespace SHADE void SHEntity::SetParent(SHEntity* newParent) noexcept { - (void)newParent; - //TODO + SHSceneManager::GetCurrentSceneGraph().SetParent(GetEID(), newParent->GetEID()); } void SHEntity::SetParent(EntityID newParentID) noexcept { - (void)newParentID; - //TODO + SHSceneManager::GetCurrentSceneGraph().SetParent(GetEID(), newParentID); } SHEntity* SHEntity::GetParent()const noexcept { - //TODO - return nullptr; + SHSceneNode* parent = SHSceneManager::GetCurrentSceneGraph().GetParent(GetEID()); + if (parent != nullptr) + return SHEntityManager::GetEntityByID(parent->GetEntityID()); + else + return nullptr; + } + + EntityID SHEntity::GetParentEID()const noexcept + { + SHSceneNode* parent = SHSceneManager::GetCurrentSceneGraph().GetParent(GetEID()); + if (parent != nullptr) + return parent->GetEntityID(); + else + return MAX_EID; } std::vectorconst& SHEntity::GetChildren()const noexcept { - //TODO - return std::vector{}; + std::vector childrenEntity; + + auto& childrenNodes = SHSceneManager::GetCurrentSceneGraph().GetChildren(GetEID()); + for (auto& childNode : childrenNodes) + { + childrenEntity.push_back(SHEntityManager::GetEntityByID(childNode->GetEntityID())); + } + + return childrenEntity; } std::vectorconst& SHEntity::GetChildrenID()const noexcept { - return std::vector{}; + std::vector childrenEntity; + + auto& childrenNodes = SHSceneManager::GetCurrentSceneGraph().GetChildren(GetEID()); + for (auto& childNode : childrenNodes) + { + childrenEntity.push_back(childNode->GetEntityID()); + } + + return childrenEntity; } } diff --git a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h index e499e260..690895e8 100644 --- a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h +++ b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h @@ -127,6 +127,13 @@ namespace SHADE ***************************************************************************/ SHEntity* GetParent()const noexcept; + /******************************************************************** + * \brief + * Get the entity ID of the parent. + * \return + * return the entity ID of the parent + ********************************************************************/ + EntityID GetParentEID() const noexcept; /************************************************************************** * \brief diff --git a/SHADE_Engine/src/ECS_Base/Events/SHEntityCreationEvent.h b/SHADE_Engine/src/ECS_Base/Events/SHEntityCreationEvent.h new file mode 100644 index 00000000..709d5147 --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/Events/SHEntityCreationEvent.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + struct SHEntityCreationEvent + { + EntityID eid; + std::vector componentTypeIDs; + EntityID parentEID; + }; +} diff --git a/SHADE_Engine/src/ECS_Base/Events/SHEntityDestroyedEvent.h b/SHADE_Engine/src/ECS_Base/Events/SHEntityDestroyedEvent.h new file mode 100644 index 00000000..770f0c4e --- /dev/null +++ b/SHADE_Engine/src/ECS_Base/Events/SHEntityDestroyedEvent.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ECS_Base/Entity/SHEntity.h" + +namespace SHADE +{ + struct SHEntityDestroyedEvent + { + EntityID eid; + }; +} diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp index 240c0b32..bbf8d400 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp +++ b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.cpp @@ -103,6 +103,18 @@ namespace SHADE SHComponentManager::AddComponent(eID, id); } + + //Link up with scene graph. + + if (parentEID != MAX_EID) + SHSceneManager::GetCurrentSceneGraph().AddNode(eID, SHSceneManager::GetCurrentSceneGraph().GetNode(parentEID)); + else + SHSceneManager::GetCurrentSceneGraph().AddNode(eID); + + //set up event stuff + SHEntityCreationEvent event{ eID,componentTypeIDs, parentEID }; + SHEventManager::BroadcastEvent(event, SH_ENTITY_CREATION_EVENT); + //(SHComponentManager::AddComponent(eID), ...); //if (entityHandle.IsValid(parentEID) == false) @@ -134,6 +146,14 @@ namespace SHADE //Call all the children to Destroy themselves first before the parent is destroyed. if (entityVec[eIndex]) { + auto& children = SHSceneManager::GetCurrentSceneGraph().GetChildren(eID); + for (auto& child : children) + { + DestroyEntity(child->GetEntityID()); + } + + SHSceneManager::GetCurrentSceneGraph().RemoveNode(eID); + //auto& children = entityVec[eIndex]->GetChildrenID(); //while(!children.empty()) //{ @@ -153,6 +173,14 @@ namespace SHADE entityHandle.RemoveHandle(eID); entityVec[eIndex].reset(nullptr); + + + + + SHEntityDestroyedEvent event{eID}; + SHEventManager::BroadcastEvent(event, SH_ENTITY_DESTROYED_EVENT); + + } } diff --git a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.h b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.h index 2d8a3ce5..f32ab2c4 100644 --- a/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.h +++ b/SHADE_Engine/src/ECS_Base/Managers/SHEntityManager.h @@ -20,6 +20,10 @@ #include "../Components/SHComponent.h" #include "../General/SHHandleGenerator.h" #include "../SHECSMacros.h" +#include "ECS_Base/Events/SHEntityCreationEvent.h" +#include "ECS_Base/Events/SHEntityDestroyedEvent.h" +#include "Scene/SHSceneManager.h" +#include "Events/SHEventManager.hpp" #include "SH_API.h" namespace SHADE @@ -125,6 +129,23 @@ namespace SHADE entityVec[eIndex]->name = name; (SHComponentManager::AddComponent(eID), ...); + //set up event stuff + std::vector typeIDVec; + (typeIDVec.push_back(ComponentFamily::GetID()), ...); + + + //Link up with scene graph. + + if (parentEID != MAX_EID) + SHSceneManager::GetCurrentSceneGraph().AddNode(eID, SHSceneManager::GetCurrentSceneGraph().GetNode(parentEID)); + else + SHSceneManager::GetCurrentSceneGraph().AddNode(eID); + + SHEntityCreationEvent event{ eID,typeIDVec,parentEID }; + SHEventManager::BroadcastEvent(event, SH_ENTITY_CREATION_EVENT); + + + /*if (entityHandle.IsValid(parentEID) == false) { entityVec[eIndex]->sceneNode.ConnectToRoot(); @@ -135,8 +156,6 @@ namespace SHADE }*/ - //Link up with scene graph. - return eID; } diff --git a/SHADE_Engine/src/ECS_Base/System/SHSystemRoutine.h b/SHADE_Engine/src/ECS_Base/System/SHSystemRoutine.h index 2b6d8dc1..ddac950b 100644 --- a/SHADE_Engine/src/ECS_Base/System/SHSystemRoutine.h +++ b/SHADE_Engine/src/ECS_Base/System/SHSystemRoutine.h @@ -41,7 +41,7 @@ namespace SHADE std::string const GetName() const noexcept; SHRoutineStats const& GetStats()const noexcept; - virtual void Execute(double dt) noexcept {}; + virtual void Execute(double dt) noexcept { (void)dt; }; }; diff --git a/SHADE_Engine/src/ECS_Base/UnitTesting/SHECSUnitTest.cpp b/SHADE_Engine/src/ECS_Base/UnitTesting/SHECSUnitTest.cpp index c9d8477b..050d0c2e 100644 --- a/SHADE_Engine/src/ECS_Base/UnitTesting/SHECSUnitTest.cpp +++ b/SHADE_Engine/src/ECS_Base/UnitTesting/SHECSUnitTest.cpp @@ -30,9 +30,9 @@ namespace SHADE SHLOG_INFO("Test for add and remove component") EntityID id1 = SHEntityManager::CreateEntity(); - EntityID id2 = SHEntityManager::CreateEntity(); - EntityID id3 = SHEntityManager::CreateEntity(); - + SHEntityManager::CreateEntity(); + SHEntityManager::CreateEntity(); + SHComponentManager::AddComponent(id1); } diff --git a/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestSystems.h b/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestSystems.h index 7231b323..12da5e37 100644 --- a/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestSystems.h +++ b/SHADE_Engine/src/ECS_Base/UnitTesting/SHTestSystems.h @@ -30,7 +30,7 @@ namespace SHADE virtual void Execute(double dt) noexcept { - + (void)dt; std::cout << GetName() << " System Version: " << GetSystem()->GetSystemVersion() << std::endl; } }; diff --git a/SHADE_Engine/src/Events/SHEvent.h b/SHADE_Engine/src/Events/SHEvent.h index 2ca6648e..6d246f3d 100644 --- a/SHADE_Engine/src/Events/SHEvent.h +++ b/SHADE_Engine/src/Events/SHEvent.h @@ -16,7 +16,17 @@ namespace SHADE struct SHEvent { SHEventIdentifier type; - SHEventDataPtr dataPtr; SHEventHandle handle; }; + + template + struct SHEventSpec : SHEvent + { + SHEventSpec(SHEventIdentifier t, SHEventHandle e, std::shared_ptr dp) + :SHEvent{ t, e }, data{ dp } {} + + std::shared_ptr data; + }; + + using SHEventPtr = std::shared_ptr; } diff --git a/SHADE_Engine/src/Events/SHEventDefines.h b/SHADE_Engine/src/Events/SHEventDefines.h index 76b403bd..f1e92b42 100644 --- a/SHADE_Engine/src/Events/SHEventDefines.h +++ b/SHADE_Engine/src/Events/SHEventDefines.h @@ -3,7 +3,8 @@ typedef uint32_t SHEventIdentifier; typedef uint32_t SHEventHandle; -typedef void* SHEventDataPtr; //Add your event identifiers here: -constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0}; \ No newline at end of file +constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0}; +constexpr SHEventIdentifier SH_ENTITY_DESTROYED_EVENT{ 1 }; +constexpr SHEventIdentifier SH_ENTITY_CREATION_EVENT{ 2 }; diff --git a/SHADE_Engine/src/Events/SHEventManager.cpp b/SHADE_Engine/src/Events/SHEventManager.cpp deleted file mode 100644 index 1cede2a0..00000000 --- a/SHADE_Engine/src/Events/SHEventManager.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/****************************************************************************** - * \file SHEventManager.cpp - * \author Loh Xiao Qi - * \brief Function Implmentations for SHEventManager - * - * \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 "SHEventManager.h" - -namespace SHADE -{ - std::unordered_map SHEventManager::packageReceiverRegistry; - std::unordered_map SHEventManager::dataEventMap; - - SHEventHandle SHEventManager::handleCounter{ 0 }; - - /**************************************************************************** - * \param ListenerConstPtr - Const pointer to listener that sent event. - * \param EventType - Templated type for every type of event - - * \brief Receives event from the listeners. - ****************************************************************************/ - void SHEventManager::CatchEvent(SHEvent event) - { - - // Do something with the event - - Broadcast(event); - } - - /**************************************************************************** - * \param ResponseFunction - function pointer from receiver to be passed - * into event manager to be called when events are broadcasted. - * \param SHEventIdentifier - package type that corresponding subscriber is - * subscribing to. - - * \brief Links a function pointer from a subscriber to a particular - * package type - ****************************************************************************/ - void SHEventManager::SubscribeTo(SHEventIdentifier pkgType, ReceiverPtr receiver) - { - RegisterReceiverToType(pkgType, receiver); - } - - template - T* SHEventManager::BroadcastEvent(T data, SHEventIdentifier eventType) - { - SHEventDataPtr ptr = new std::byte[sizeof(data)]; - - std::memcpy(ptr, &data, sizeof(data)); - - CatchEvent( - { - eventType, - ptr, - handleCounter++ - } - ); - - return reinterpret_cast(ptr); - } - - /**************************************************************************** - * \param ReceiverPtr - Pointer to receiver - * \param ListenerConstPtr - Const pointer to listener that receiver is - * subscribing to. - - * \brief Registers receiver as a subscriber to listener in the registry. - ****************************************************************************/ - void SHEventManager::RegisterReceiverToType( - SHEventIdentifier pkgType, ReceiverPtr receiver) - { - if (packageReceiverRegistry.contains(pkgType)) - { - packageReceiverRegistry[pkgType].emplace_back(receiver); - } - else - { - packageReceiverRegistry.emplace(pkgType, std::vector{ receiver }); - } - } - - /**************************************************************************** - * \param ListenerConstPtr - Const pointer to listener that sent event. - * \param EventType - Event data - - * \brief Broadcast event to all receivers that are subscribed to this - * listener. - ****************************************************************************/ - void SHEventManager::Broadcast(SHEvent const& event) - { - ResponseVec& receivers{ packageReceiverRegistry[event.type] }; - for (auto& receiver : receivers) - { - receiver->Receive(event); - } - - //auto& funcs{ ackageReceiverRegistry[event.GetType()] }; - //for (auto func : funcs) - //{ - // func(event.GetData()); - //} - } -} diff --git a/SHADE_Engine/src/Events/SHEventManager.h b/SHADE_Engine/src/Events/SHEventManager.hpp similarity index 67% rename from SHADE_Engine/src/Events/SHEventManager.h rename to SHADE_Engine/src/Events/SHEventManager.hpp index f2f19fef..f511518a 100644 --- a/SHADE_Engine/src/Events/SHEventManager.h +++ b/SHADE_Engine/src/Events/SHEventManager.hpp @@ -1,5 +1,5 @@ /****************************************************************************** - * \file SHEventManager.h + * \file SHEventManager.hpp * \author Loh Xiao Qi * \brief Class declaration for event manager. * @@ -9,10 +9,9 @@ ******************************************************************************/ #pragma once +#include "SHpch.h" #include "SHEvent.h" #include "SHEventReceiver.h" -#include -#include /****************************************************************************** INSTRUCTIONS FOR USE: @@ -24,11 +23,16 @@ 3. When ready to send the event, call SHEventManager::BroadcastEvent(exampleClass, EVENT_IDENTIFIER); - Headers required: SHEventManager.h + NOTE: If your custom struct to contain data requires a deep copy, please + overload the assignment operator accordingly. It is fine to send + a single object of a basic type such as int/float. + + Headers required: SHEventManager.hpp On Receiver side: 1. Create a function with the signature: - SHEventHandle FunctionName(SHEvent); + SHEventHandle FunctionName(SHEventPtr); + 2. In the init function of the class, copy the below in and replace the necessary: @@ -42,25 +46,71 @@ 3. Note: The EventIdentifier should match all that is defined in SHEventDefines.h so check there. When the receiver catches the event, it - needs to know the struct that the broadcaster is using to cast the void* - properly. + needs to know the struct that the broadcaster is using to cast the event + ptr as such: - Headers required: SHEventManager.h, SHEventReceiver.h + reinterpret_cast>>(event) + + 4. Inside the new ptr should be a shared pointer of const CustomClass type. + + Headers required: SHEventManager.hpp, SHEventReceiver.h If you have any questions/suggestions for improvement lmk. ******************************************************************************/ namespace SHADE { - using ResponseFunction = std::function; + //using ResponseFunction = std::function; using ReceiverPtr = std::shared_ptr; using ResponseVec = std::vector; - using StaticResponseVec = std::vector; using EventManagerListener = std::function; + class SHEventManager { + private: + + // Registry for broadcasters and subscribers + inline static std::unordered_map packageReceiverRegistry; + + inline static SHEventHandle handleCounter {0}; + + /**************************************************************************** + * \param ListenerConstPtr - Const pointer to listener that sent event. + * \param EventType - Event data + + * \brief Broadcast event to all receivers that are subscribed to this + * listener. + ****************************************************************************/ + static void Broadcast(SHEventPtr event) + { + ResponseVec& receivers{ packageReceiverRegistry[event->type] }; + for (auto& receiver : receivers) + { + receiver->Receive(event); + } + } + + /**************************************************************************** + * \param ReceiverPtr - Pointer to receiver + * \param ListenerConstPtr - Const pointer to listener that receiver is + * subscribing to. + + * \brief Registers receiver as a subscriber to listener in the registry. + ****************************************************************************/ + static void RegisterReceiverToType(SHEventIdentifier pkgType, ReceiverPtr receiver) + { + if (packageReceiverRegistry.find(pkgType) == packageReceiverRegistry.end()) + { + packageReceiverRegistry.emplace(pkgType, std::vector{ receiver }); + } + else + { + packageReceiverRegistry[pkgType].emplace_back(receiver); + } + } + public: /**************************************************************************** @@ -69,7 +119,13 @@ namespace SHADE * \brief Receives event from the listeners. ****************************************************************************/ - static void CatchEvent(SHEvent); + static void CatchEvent(SHEventPtr event) + { + + // Do something with the event + + Broadcast(event); + } /**************************************************************************** * \param ResponseFunction - function pointer from receiver to be passed @@ -80,37 +136,20 @@ namespace SHADE * \brief Links a function pointer from a subscriber to a particular * package type ****************************************************************************/ - static void SubscribeTo(SHEventIdentifier, ReceiverPtr); + static void SubscribeTo(SHEventIdentifier pkgType, ReceiverPtr receiver) + { + RegisterReceiverToType(pkgType, receiver); + } template - static T* BroadcastEvent(T data, SHEventIdentifier eventType); - - private: - - // Registry for broadcasters and subscribers - static std::unordered_map packageReceiverRegistry; - static std::unordered_map dataEventMap; - - static SHEventHandle handleCounter; - - /**************************************************************************** - * \param ListenerConstPtr - Const pointer to listener that sent event. - * \param EventType - Event data - - * \brief Broadcast event to all receivers that are subscribed to this - * listener. - ****************************************************************************/ - static void Broadcast(SHEvent const&); - - /**************************************************************************** - * \param ReceiverPtr - Pointer to receiver - * \param ListenerConstPtr - Const pointer to listener that receiver is - * subscribing to. - - * \brief Registers receiver as a subscriber to listener in the registry. - ****************************************************************************/ - static void RegisterReceiverToType(SHEventIdentifier, ReceiverPtr); + static void BroadcastEvent(T data, SHEventIdentifier eventType) + { + std::shared_ptr ptr = std::make_shared(data); + CatchEvent( + std::make_shared>(eventType, handleCounter++, ptr) + ); + } }; } diff --git a/SHADE_Engine/src/Events/SHEventReceiver.h b/SHADE_Engine/src/Events/SHEventReceiver.h index f968e579..e6e5e757 100644 --- a/SHADE_Engine/src/Events/SHEventReceiver.h +++ b/SHADE_Engine/src/Events/SHEventReceiver.h @@ -8,7 +8,7 @@ namespace SHADE { private: public: - virtual void Receive(SHEvent) = 0; + virtual void Receive(SHEventPtr) = 0; }; template @@ -16,16 +16,16 @@ namespace SHADE { private: T* object; - SHEventHandle(T::*callback)(SHEvent); + SHEventHandle(T::*callback)(SHEventPtr); public: - SHEventReceiverSpec(T* obj, void(T::* cb)(SHEventDataPtr)) + SHEventReceiverSpec(T* obj, void(T::* cb)(SHEventPtr)) :SHEventReceiver(), object{ obj }, callback{ cb } { } - void Receive(SHEvent evt) override + void Receive(SHEventPtr evt) override { (object->*callback)(evt); } diff --git a/SHADE_Engine/src/Scene/SHScene.h b/SHADE_Engine/src/Scene/SHScene.h index 18aeffdc..372981a6 100644 --- a/SHADE_Engine/src/Scene/SHScene.h +++ b/SHADE_Engine/src/Scene/SHScene.h @@ -12,6 +12,7 @@ #define SH_SCENE_H #include +#include "SHSceneGraph.h" namespace SHADE { @@ -19,15 +20,19 @@ namespace SHADE class SHScene { private: + SHSceneGraph sceneGraph; + protected: SHScene() = default; public: + virtual ~SHScene() = default; + std::string sceneName; - virtual ~SHScene() = default; + SHSceneGraph& GetSceneGraph() noexcept { return sceneGraph; } virtual void Load() = 0; virtual void Init() = 0; diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.cpp b/SHADE_Engine/src/Scene/SHSceneGraph.cpp index 9fddf10e..821388b0 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.cpp +++ b/SHADE_Engine/src/Scene/SHSceneGraph.cpp @@ -76,7 +76,10 @@ namespace SHADE SHSceneGraph::SHSceneGraph() noexcept : root { nullptr } - {} + { + // The root is set to the maximum entity. It should not be interfaced with. + root = AllocateNode(MAX_EID); + } SHSceneGraph::~SHSceneGraph() noexcept { @@ -90,6 +93,8 @@ namespace SHADE for (auto* node : entityNodeMap | std::views::values) ReleaseNode(node); + delete root; + #ifdef _DEBUG SHLOG_INFO("Scene Graph Destroyed Successfully!") #endif @@ -99,23 +104,38 @@ namespace SHADE /* Getter Function Definitions */ /*-----------------------------------------------------------------------------------*/ + EntityID SHSceneNode::GetEntityID() const noexcept + { + return entityID; + } + + SHSceneNode* SHSceneNode::GetParent() const noexcept + { + return parent; + } + + const std::vector& SHSceneNode::GetChildren() const noexcept + { + return children; + } + SHSceneNode* SHSceneNode::GetChild(EntityID childID) const noexcept { + //////////////////////////////////////// // Error handling + if (!SHEntityManager::IsValidEID(childID)) { - if (!SHEntityManager::IsValidEID(childID)) - { - SHLOG_ERROR("Child Entity {} is invalid! Unable to get child from Entity {}", childID, entityID) - return nullptr; - } - - if (children.empty()) - { - SHLOG_WARNING("Entity {} has no children!", entityID) - return nullptr; - } + SHLOG_ERROR("Child Entity {} is invalid! Unable to get child from Entity {}", childID, entityID) + return nullptr; } + if (children.empty()) + { + SHLOG_WARNING("Entity {} has no children!", entityID) + return nullptr; + } + //////////////////////////////////////// + // Find child const auto ENTITY_MATCH = [&](const SHSceneNode* node) { return node->GetEntityID() == childID; }; @@ -129,17 +149,19 @@ namespace SHADE return *CHILD_ITER; } - SHSceneNode* SHSceneGraph::GetRoot() const noexcept + const SHSceneNode* SHSceneGraph::GetRoot() const noexcept { if (root != nullptr) return root; SHLOG_WARNING("Scene has no root object!") - return nullptr; + return nullptr; } SHSceneNode* SHSceneGraph::GetNode(EntityID entityID) const noexcept { + //////////////////////////////////////// + // Error handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid! Unable to Get Scene node!", entityID) @@ -152,12 +174,15 @@ namespace SHADE SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to Get Scene node!", entityID) return nullptr; } + //////////////////////////////////////// return NODE_ITER->second; } SHSceneNode* SHSceneGraph::GetParent(EntityID entityID) const noexcept { + //////////////////////////////////////// + // Error handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid! Unable to get Parent node!", entityID) @@ -170,13 +195,15 @@ namespace SHADE SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to get Parent node!", entityID) return nullptr; } + //////////////////////////////////////// return NODE_ITER->second->GetParent(); } SHSceneNode* SHSceneGraph::GetChild(EntityID entityID, SHSceneNode* childNode) const noexcept { - // Error Handling + //////////////////////////////////////// + // Error handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid!", entityID) @@ -203,12 +230,15 @@ namespace SHADE SHLOG_WARNING("Entity {} is not a child of Entity {}!", childNode->GetEntityID(), entityID) return nullptr; } + //////////////////////////////////////// return *CHILD_ITER; } SHSceneNode* SHSceneGraph::GetChild(EntityID entityID, EntityID childEntityID) const noexcept { + //////////////////////////////////////// + // Error handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid!", entityID) @@ -221,14 +251,15 @@ namespace SHADE SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) return nullptr; } + //////////////////////////////////////// return NODE_ITER->second->GetChild(childEntityID); } const std::vector& SHSceneGraph::GetChildren(EntityID entityID) const noexcept { - // TODO(Diren): Discuss with team best way to handle this - + //////////////////////////////////////// + // Error handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid!", entityID) @@ -241,6 +272,7 @@ namespace SHADE SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) return root->GetChildren(); } + //////////////////////////////////////// return NODE_ITER->second->GetChildren(); } @@ -252,11 +284,17 @@ namespace SHADE void SHSceneNode::SetParent(SHSceneNode* parentNode) noexcept { if (parentNode == nullptr) + { SHLOG_WARNING("Removing Entity {}'s parent", entityID) + } + // Handle self assignment if (parentNode == parent) return; + if (parent) + parent->RemoveChild(this); + parent = parentNode; // Update parent's children parent->AddChild(this); @@ -264,6 +302,8 @@ namespace SHADE void SHSceneGraph::SetParent(EntityID entityID, SHSceneNode* parent) const noexcept { + //////////////////////////////////////// + // Error Handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid!", entityID) @@ -276,12 +316,15 @@ namespace SHADE SHLOG_WARNING("Entity {} cannot be found in the scene!", entityID) return; } + //////////////////////////////////////// NODE_ITER->second->SetParent(parent); } void SHSceneGraph::SetParent(EntityID entityID, EntityID parent) const noexcept { + //////////////////////////////////////// + // Error Handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid! Unable to set parent of an invalid entity!", entityID) @@ -301,12 +344,13 @@ namespace SHADE return; } - auto PARENT_ITER = entityNodeMap.find(entityID); + auto PARENT_ITER = entityNodeMap.find(parent); if (PARENT_ITER == entityNodeMap.end()) { SHLOG_WARNING("Entity {} cannot be found in the scene! Unable to parent to Entity {}", parent, entityID) return; } + //////////////////////////////////////// SHSceneNode* currentNode = NODE_ITER->second; currentNode->SetParent(PARENT_ITER->second); @@ -318,50 +362,69 @@ namespace SHADE void SHSceneNode::AddChild(SHSceneNode* newChild) noexcept { + //////////////////////////////////////// + // Error Handling if (newChild == nullptr) { SHLOG_WARNING("Attempting to add a non-existent child to an entity!") return; } + //////////////////////////////////////// + if (newChild->parent) + newChild->parent->RemoveChild(newChild); + + newChild->parent = this; children.emplace_back(newChild); } bool SHSceneNode::RemoveChild(EntityID childID) noexcept { + //////////////////////////////////////// + // Error Handling if (!SHEntityManager::IsValidEID(childID)) { SHLOG_ERROR("Entity {} is invalid!", childID) return false; } + //////////////////////////////////////// - SHSceneNode* removedChild = nullptr; - const auto ENTITY_MATCH = [&](SHSceneNode* node) + auto childIter = std::find_if(children.begin(), children.end(), [&](SHSceneNode* node) { - if (node->GetEntityID() == childID) - { - removedChild = node; - return true; - } + return node->GetEntityID() == childID; + }); + if (childIter == children.end()) + { + SHLOG_WARNING("Unable to remove Entity {} from Entity {} since it is not it's child!", childID, entityID) return false; - }; + } - children.end() = std::remove_if(children.begin(), children.end(), ENTITY_MATCH); - removedChild->parent = nullptr; + (*childIter)->parent = nullptr; + childIter = children.erase(childIter); - return removedChild == nullptr; + return true; } bool SHSceneNode::RemoveChild(SHSceneNode* childToRemove) noexcept { + //////////////////////////////////////// + // Error Handling if (childToRemove == nullptr) { SHLOG_WARNING("Attempting to remove non-existent child from Entity {}", entityID) return false; } + //////////////////////////////////////// - children.end() = std::remove(children.begin(), children.end(), childToRemove); + auto childIter = std::find(children.begin(), children.end(), childToRemove); + if (childIter == children.end()) + { + SHLOG_WARNING("Unable to remove Entity {} from Entity {} since it is not it's child!", childToRemove->entityID, entityID) + return false; + } + + childIter = children.erase(childIter); childToRemove->parent = nullptr; return true; @@ -375,22 +438,28 @@ namespace SHADE children.clear(); } - SHSceneNode* SHSceneGraph::AddNode(EntityID entityID, SHSceneNode* parent) { + //////////////////////////////////////// + // Error Handling if (!SHEntityManager::IsValidEID(entityID)) { SHLOG_ERROR("Entity {} is invalid!", entityID) return nullptr; } + //////////////////////////////////////// if (auto NODE_ITER = entityNodeMap.find(entityID); NODE_ITER != entityNodeMap.end()) { SHLOG_WARNING("Entity {} already exists in the scene!", entityID) return NODE_ITER->second; } - + SHSceneNode* newNode = AllocateNode(entityID); + + if (parent == nullptr) + parent = root; + newNode->SetParent(parent); return newNode; diff --git a/SHADE_Engine/src/Scene/SHSceneGraph.h b/SHADE_Engine/src/Scene/SHSceneGraph.h index 20830065..38fcc414 100644 --- a/SHADE_Engine/src/Scene/SHSceneGraph.h +++ b/SHADE_Engine/src/Scene/SHSceneGraph.h @@ -14,6 +14,7 @@ // Project Headers #include "ECS_Base/Entity/SHEntity.h" +#include "SH_API.h" namespace SHADE { @@ -21,7 +22,7 @@ namespace SHADE /* Type Definitions */ /*-----------------------------------------------------------------------------------*/ - class SHSceneNode + class SH_API SHSceneNode { public: /*---------------------------------------------------------------------------------*/ @@ -34,40 +35,40 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - ~SHSceneNode () = default; + ~SHSceneNode () = default; - SHSceneNode (EntityID eid, SHSceneNode* parent = nullptr) noexcept; - SHSceneNode (const SHSceneNode& rhs) noexcept; - SHSceneNode (SHSceneNode&& rhs) noexcept; - SHSceneNode& operator= (const SHSceneNode& rhs) noexcept; - SHSceneNode& operator= (SHSceneNode&& rhs) noexcept; + SHSceneNode (EntityID eid, SHSceneNode* parent = nullptr) noexcept; + SHSceneNode (const SHSceneNode& rhs) noexcept; + SHSceneNode (SHSceneNode&& rhs) noexcept; + SHSceneNode& operator= (const SHSceneNode& rhs) noexcept; + SHSceneNode& operator= (SHSceneNode&& rhs) noexcept; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] EntityID GetEntityID () const noexcept { return entityID ;} - [[nodiscard]] SHSceneNode* GetParent () const noexcept { return parent; } - [[nodiscard]] std::vector& GetChildren () noexcept { return children; } + [[nodiscard]] EntityID GetEntityID () const noexcept; + [[nodiscard]] SHSceneNode* GetParent () const noexcept; + [[nodiscard]] const std::vector& GetChildren () const noexcept; - [[nodiscard]] SHSceneNode* GetChild (EntityID childID) const noexcept; + [[nodiscard]] SHSceneNode* GetChild (EntityID childID) const noexcept; /*---------------------------------------------------------------------------------*/ /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetParent (SHSceneNode* parentNode) noexcept; + void SetParent (SHSceneNode* parentNode) noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - void AddChild (SHSceneNode* newChild) noexcept; + void AddChild (SHSceneNode* newChild) noexcept; - bool RemoveChild (EntityID childID) noexcept; - bool RemoveChild (SHSceneNode* childToRemove) noexcept; + bool RemoveChild (EntityID childID) noexcept; + bool RemoveChild (SHSceneNode* childToRemove) noexcept; - void RemoveAllChildren () noexcept; + void RemoveAllChildren () noexcept; private: EntityID entityID; @@ -75,7 +76,7 @@ namespace SHADE std::vector children; }; - class SHSceneGraph + class SH_API SHSceneGraph { public: /*---------------------------------------------------------------------------------*/ @@ -88,19 +89,19 @@ namespace SHADE /* Constructors & Destructor */ /*---------------------------------------------------------------------------------*/ - SHSceneGraph () noexcept; - ~SHSceneGraph () noexcept; + SHSceneGraph () noexcept; + ~SHSceneGraph () noexcept; - SHSceneGraph (const SHSceneGraph&) = delete; - SHSceneGraph (SHSceneGraph&&) = delete; - SHSceneGraph& operator= (const SHSceneGraph&) = delete; - SHSceneGraph& operator= (SHSceneGraph&&) = delete; + SHSceneGraph (const SHSceneGraph&) = delete; + SHSceneGraph (SHSceneGraph&&) = delete; + SHSceneGraph& operator= (const SHSceneGraph&) = delete; + SHSceneGraph& operator= (SHSceneGraph&&) = delete; /*---------------------------------------------------------------------------------*/ /* Getter Functions */ /*---------------------------------------------------------------------------------*/ - [[nodiscard]] SHSceneNode* GetRoot () const noexcept; + [[nodiscard]] const SHSceneNode* GetRoot () const noexcept; [[nodiscard]] SHSceneNode* GetNode (EntityID entityID) const noexcept; [[nodiscard]] SHSceneNode* GetParent (EntityID entityID) const noexcept; [[nodiscard]] SHSceneNode* GetChild (EntityID entityID, SHSceneNode* childNode) const noexcept; @@ -111,17 +112,17 @@ namespace SHADE /* Setter Functions */ /*---------------------------------------------------------------------------------*/ - void SetParent (EntityID entityID, SHSceneNode* parent) const noexcept; - void SetParent (EntityID entityID, EntityID parent) const noexcept; + void SetParent (EntityID entityID, SHSceneNode* parent) const noexcept; + void SetParent (EntityID entityID, EntityID parent) const noexcept; /*---------------------------------------------------------------------------------*/ /* Function Members */ /*---------------------------------------------------------------------------------*/ - SHSceneNode* AddNode (EntityID entityID, SHSceneNode* parent = nullptr); - bool RemoveNode (EntityID entityID) noexcept; - bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; - void Reset () noexcept; + SHSceneNode* AddNode (EntityID entityID, SHSceneNode* parent = nullptr); + bool RemoveNode (EntityID entityID) noexcept; + bool RemoveNode (SHSceneNode* nodeToRemove) noexcept; + void Reset () noexcept; private: /*---------------------------------------------------------------------------------*/ @@ -136,7 +137,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ SHSceneNode* AllocateNode (EntityID entityID); - void ReleaseNode (SHSceneNode* node) noexcept; + void ReleaseNode (SHSceneNode* node) noexcept; }; diff --git a/SHADE_Engine/src/Scene/SHSceneManager.cpp b/SHADE_Engine/src/Scene/SHSceneManager.cpp index d5223af8..2baf0b9c 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -37,6 +37,12 @@ namespace SHADE std::function SHSceneManager::newScene = []() {}; //void (*SHSceneManager::prevSceneCreate)() = []() {}; + + SHSceneGraph& SHSceneManager::GetCurrentSceneGraph() noexcept + { + return currentScene->GetSceneGraph(); + } + void SHSceneManager::UpdateSceneManager() noexcept { if (sceneChanged == false) diff --git a/SHADE_Engine/src/Scene/SHSceneManager.h b/SHADE_Engine/src/Scene/SHSceneManager.h index 4139309d..72db1274 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.h +++ b/SHADE_Engine/src/Scene/SHSceneManager.h @@ -20,7 +20,7 @@ namespace SHADE { - class SHSceneManager + class SH_API SHSceneManager { private: //boolean to check if the scene has been changed @@ -57,6 +57,15 @@ namespace SHADE //boolean to check if the programme has been terminated. static bool quit; + /******************************************************************** + * \brief + * Get the scene graph of the current scene. + * \return + * A reference to the scene graph of the current active scene. + ********************************************************************/ + static SHSceneGraph& GetCurrentSceneGraph() noexcept; + + /*!************************************************************************* * \brief * Initialize scene manager and loads a default scene diff --git a/generate.bat b/generate.bat index ce7f2916..b81fce81 100644 --- a/generate.bat +++ b/generate.bat @@ -1,2 +1,5 @@ +erase /s /q *.vcxproj +erase /s /q *.vcxproj.filters + call Premake\premake5 vs2019 PAUSE \ No newline at end of file