From a785a972e4b901c9c1fd88f91750d69551d55a55 Mon Sep 17 00:00:00 2001 From: maverickdgg Date: Fri, 24 Mar 2023 04:22:51 +0800 Subject: [PATCH] Navigation Fix --- Assets/Scenes/NavigationTest.shade | 273 +++++++++++++++++- .../AIRework/NavigationTestScript.cs | 37 +++ .../AIRework/NavigationTestScript.cs.shmeta | 3 + .../src/Application/SBApplication.cpp | 1 + SHADE_Engine/src/Common/SHAllComponents.h | 3 +- .../Inspector/SHEditorInspector.cpp | 6 + .../src/Navigation/SHNavigationComponent.cpp | 36 ++- .../src/Navigation/SHNavigationComponent.h | 39 ++- .../src/Navigation/SHNavigationSystem.cpp | 264 ++++++++++++++--- .../src/Navigation/SHNavigationSystem.h | 30 +- .../src/Serialization/SHSerialization.cpp | 8 + SHADE_Managed/src/Components/Navigation.cxx | 58 ++++ SHADE_Managed/src/Components/Navigation.hxx | 35 +++ SHADE_Managed/src/Engine/ECS.cxx | 3 +- 14 files changed, 723 insertions(+), 73 deletions(-) create mode 100644 Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs create mode 100644 Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs.shmeta create mode 100644 SHADE_Managed/src/Components/Navigation.cxx create mode 100644 SHADE_Managed/src/Components/Navigation.hxx diff --git a/Assets/Scenes/NavigationTest.shade b/Assets/Scenes/NavigationTest.shade index cd358faa..454f56a2 100644 --- a/Assets/Scenes/NavigationTest.shade +++ b/Assets/Scenes/NavigationTest.shade @@ -4,21 +4,10 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: 0, y: 0, z: 0} + Translate: {x: 0, y: 10.2736483, z: 0} + Rotate: {x: -1.48352981, y: 1.5, z: 0.5} Scale: {x: 1, y: 1, z: 1} IsActive: true - Camera Component: - Position: {x: 0, y: 0, z: 0} - Pitch: 0 - Yaw: 0 - Roll: 0 - Width: 1920 - Near: 0.00999999978 - Far: 10000 - Perspective: true - FOV: 90 - IsActive: true Scripts: ~ - EID: 1 Name: Floor @@ -56,9 +45,9 @@ NumberOfChildren: 0 Components: Transform Component: - Translate: {x: 0, y: 0, z: 0} - Rotate: {x: -0, y: 0, z: -0} - Scale: {x: 1, y: 1, z: 1} + Translate: {x: 11, y: 0, z: 0} + Rotate: {x: -0, y: 1.57079637, z: -0} + Scale: {x: 10.6225176, y: 1, z: 1} IsActive: true Renderable Component: Mesh: 142652392 @@ -76,4 +65,256 @@ Position Offset: {x: 0, y: 0, z: 0} Rotation Offset: {x: 0, y: 0, z: 0} IsActive: true + Scripts: ~ +- EID: 4 + Name: Wall + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0, z: -11.2958097} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 10.6225176, y: 1, z: 1} + IsActive: true + Renderable Component: + Mesh: 142652392 + Material: 126223465 + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 0 + Type: Box + Half Extents: {x: 2.5, y: 1, z: 1.60000002} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 5 + Name: Wall + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0, z: 11} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 10.6225176, y: 1, z: 1} + IsActive: true + Renderable Component: + Mesh: 142652392 + Material: 126223465 + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 0 + Type: Box + Half Extents: {x: 2.5, y: 1, z: 1.60000002} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 6 + Name: Wall + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 6.06437206, y: 0, z: -5.60716629} + Rotate: {x: -0, y: 1.57079601, z: -0} + Scale: {x: 4.99989605, y: 1, z: 0.999986947} + IsActive: true + Renderable Component: + Mesh: 142652392 + Material: 126223465 + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 0 + Type: Box + Half Extents: {x: 2.5, y: 1, z: 1.60000002} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 7 + Name: Wall + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -11, y: 0, z: 0} + Rotate: {x: -0, y: 1.57079637, z: -0} + Scale: {x: 10.6225176, y: 1, z: 1} + IsActive: true + Renderable Component: + Mesh: 142652392 + Material: 126223465 + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 0 + Type: Box + Half Extents: {x: 2.5, y: 1, z: 1.60000002} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 8 + Name: Wall + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -4.70212746, y: 0, z: -0.00226712227} + Rotate: {x: -0, y: 1.57079601, z: -0} + Scale: {x: 4.99982977, y: 1, z: 0.999978602} + IsActive: true + Renderable Component: + Mesh: 142652392 + Material: 126223465 + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 0 + Type: Box + Half Extents: {x: 2.5, y: 1, z: 1.60000002} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 9 + Name: Wall + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 1.46194017, y: 0, z: 0.71579361} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 4.99985838, y: 1, z: 0.999982238} + IsActive: true + Renderable Component: + Mesh: 142652392 + Material: 126223465 + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 0 + Type: Box + Half Extents: {x: 2.5, y: 1, z: 1.60000002} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 10 + Name: Wall + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -2.30867815, y: 0, z: -6.02849674} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 4, y: 1, z: 0.999974966} + IsActive: true + Renderable Component: + Mesh: 142652392 + Material: 126223465 + IsActive: true + Collider Component: + Colliders: + - Is Trigger: false + Collision Tag: 0 + Type: Box + Half Extents: {x: 2.5, y: 1, z: 1.60000002} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Rotation Offset: {x: 0, y: 0, z: 0} + IsActive: true + Scripts: ~ +- EID: 11 + Name: TestAI + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 8.5, y: -1, z: -8.20610714} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 5, y: 5, z: 5} + IsActive: true + Renderable Component: + Mesh: 140639624 + Material: 131956078 + IsActive: true + Navigation Component: + Target: {x: 0, y: 0, z: 0} + Forward: {x: 0, y: 0, z: 0} + Recalculate Path: true + Unreachable Target: false + Acceptance threshold: 0.100000001 + IsActive: true + Scripts: + - Type: SHADE_Scripting.Gameplay.AIBehaviour.AIRework.NavigationTestScript + Enabled: true + endPoint: 12 + speed: 3 +- EID: 12 + Name: EndPoint + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -0.940230131, y: -1, z: -2.05140448} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 5, y: 5, z: 5} + IsActive: true + Renderable Component: + Mesh: 140639624 + Material: 131956078 + IsActive: true + Scripts: ~ +- EID: 13 + Name: Camera + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 10.2736483, z: 0} + Rotate: {x: -1.48352981, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + IsActive: true + Camera Component: + Position: {x: 0, y: 0, z: 0} + Pitch: -85 + Yaw: 0 + Roll: 0 + Width: 1920 + Near: 0.00999999978 + Far: 10000 + Perspective: true + FOV: 90 + IsActive: true Scripts: ~ \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs b/Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs new file mode 100644 index 00000000..c8687820 --- /dev/null +++ b/Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SHADE; +using static System.IO.Enumeration.FileSystemEnumerable; + +namespace SHADE_Scripting.Gameplay.AIBehaviour.AIRework +{ + public class NavigationTestScript :Script + { + public GameObject endPoint; + + public float speed = 1.0f; + + protected override void start() + { + + } + + protected override void update() + { + Navigation nav = GetComponent(); + Transform transform = GetComponent(); + if (nav && transform) + { + Transform endTransform = endPoint.GetComponent(); + if(endTransform) + nav.MoveTo(endTransform.GlobalPosition); + transform.LocalPosition = transform.LocalPosition + ( nav.GetForward() * Time.DeltaTimeF * speed); + + } + } + + } +} diff --git a/Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs.shmeta b/Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs.shmeta new file mode 100644 index 00000000..3d8685a5 --- /dev/null +++ b/Assets/Scripts/Gameplay/AIBehaviour/AIRework/NavigationTestScript.cs.shmeta @@ -0,0 +1,3 @@ +Name: NavigationTestScript +ID: 162476480 +Type: 9 diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index 93183a4f..c46bc7eb 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -131,6 +131,7 @@ namespace Sandbox SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); #endif + SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); SHSystemManager::RegisterRoutine(); diff --git a/SHADE_Engine/src/Common/SHAllComponents.h b/SHADE_Engine/src/Common/SHAllComponents.h index 32efee1f..21a87dfd 100644 --- a/SHADE_Engine/src/Common/SHAllComponents.h +++ b/SHADE_Engine/src/Common/SHAllComponents.h @@ -15,4 +15,5 @@ #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "AudioSystem/SHAudioListenerComponent.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" -#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h" \ No newline at end of file +#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h" +#include "Navigation/SHNavigationComponent.h" diff --git a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp index e9da2f09..701944ad 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Inspector/SHEditorInspector.cpp @@ -27,6 +27,7 @@ #include "AudioSystem/SHAudioListenerComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h" +#include "Navigation/SHNavigationComponent.h" #include "Camera/SHCameraSystem.h" #include "FRC/SHFramerateController.h" @@ -193,6 +194,10 @@ namespace SHADE { DrawComponent(particleComponent); } + if (auto navigationComponent = SHComponentManager::GetComponent_s(eid)) + { + DrawComponent(navigationComponent); + } ImGui::Separator(); // Render Scripts SHScriptEngine* scriptEngine = static_cast(SHSystemManager::GetSystem()); @@ -219,6 +224,7 @@ namespace SHADE DrawAddComponentWithEnforcedComponentButton(eid); DrawAddComponentWithEnforcedComponentButton(eid); DrawAddComponentWithEnforcedComponentButton(eid); + DrawAddComponentWithEnforcedComponentButton(eid); //DrawAddComponentWithEnforcedComponentButton(eid); ImGui::EndMenu(); diff --git a/SHADE_Engine/src/Navigation/SHNavigationComponent.cpp b/SHADE_Engine/src/Navigation/SHNavigationComponent.cpp index 3a59d5fe..c50949ec 100644 --- a/SHADE_Engine/src/Navigation/SHNavigationComponent.cpp +++ b/SHADE_Engine/src/Navigation/SHNavigationComponent.cpp @@ -4,8 +4,11 @@ namespace SHADE { + uint16_t NavigationGridIndex::numColumns = 8; + + SHNavigationComponent::SHNavigationComponent() - :target{ 0.0f }, path{}, threshold{0.1f}, recalculatePath{false}, unreachableTarget{false} + :target{ 0.0f }, path{}, threshold{ 0.1f }, recalculatePath{ false }, unreachableTarget{ false }, forward{0.0f} { } @@ -21,6 +24,16 @@ namespace SHADE return forward; } + bool SHNavigationComponent::GetRecalculatePath() const noexcept + { + return recalculatePath; + } + + bool SHNavigationComponent::GetUnreachableTarget() const noexcept + { + return unreachableTarget; + } + void SHNavigationComponent::SetTarget(SHVec3 value) noexcept { @@ -34,5 +47,26 @@ namespace SHADE } + void SHNavigationComponent::EmptySetBool(bool value) noexcept + { + + } + + +}//namespace SHADE + + +RTTR_REGISTRATION +{ + using namespace SHADE; + using namespace rttr; + + registration::class_("Navigation Component") + .property("Target", &SHNavigationComponent::GetTarget, &SHNavigationComponent::SetTarget) + .property("Forward", &SHNavigationComponent::GetForward, &SHNavigationComponent::EmptySetForward) + .property("Recalculate Path", &SHNavigationComponent::GetRecalculatePath, &SHNavigationComponent::EmptySetBool) + .property("Unreachable Target", &SHNavigationComponent::GetUnreachableTarget, &SHNavigationComponent::EmptySetBool) + .property("Acceptance threshold", &SHNavigationComponent::threshold) + ; } diff --git a/SHADE_Engine/src/Navigation/SHNavigationComponent.h b/SHADE_Engine/src/Navigation/SHNavigationComponent.h index 1552be60..be23521d 100644 --- a/SHADE_Engine/src/Navigation/SHNavigationComponent.h +++ b/SHADE_Engine/src/Navigation/SHNavigationComponent.h @@ -14,7 +14,32 @@ namespace SHADE { - using NavigationGridIndex = std::pair; + struct NavigationGridIndex + { + uint16_t row; + uint16_t column; + + static uint16_t numColumns; + + bool operator==(NavigationGridIndex const& rhs) const noexcept + { + return row == rhs.row && column == rhs.column; + } + + bool operator!=(NavigationGridIndex const& rhs) const noexcept + { + return row != rhs.row || column != rhs.column; + } + + bool operator<(NavigationGridIndex const& rhs) const noexcept + { + return (row * numColumns + column) < (rhs.row * numColumns + rhs.column); + } + + }; + + + #define NullGridIndex 9999; class SH_API SHNavigationComponent final: public SHComponent @@ -26,8 +51,7 @@ namespace SHADE SHVec3 forward; //The path to follow to reach the target. std::queue path; - //The distance threshold that indicates when the entity has reached the navigation grid. - float threshold; + //The flag to check against to indicate whether to recalculate path bool recalculatePath; //The flag to set if the target is unreachable. @@ -35,6 +59,9 @@ namespace SHADE public: friend class SHNavigationSystem; + //The distance threshold that indicates when the entity has reached the navigation grid. + float threshold; + SHNavigationComponent(); virtual ~SHNavigationComponent() = default; @@ -55,6 +82,11 @@ namespace SHADE ********************************************************************/ SHVec3 GetForward() const noexcept; + bool GetRecalculatePath() const noexcept; + + bool GetUnreachableTarget() const noexcept; + + /******************************************************************** * \brief @@ -77,6 +109,7 @@ namespace SHADE ********************************************************************/ void EmptySetForward(SHVec3 value) noexcept; + void EmptySetBool(bool value) noexcept; RTTR_ENABLE() protected: diff --git a/SHADE_Engine/src/Navigation/SHNavigationSystem.cpp b/SHADE_Engine/src/Navigation/SHNavigationSystem.cpp index 8c97162e..56778771 100644 --- a/SHADE_Engine/src/Navigation/SHNavigationSystem.cpp +++ b/SHADE_Engine/src/Navigation/SHNavigationSystem.cpp @@ -5,16 +5,25 @@ #include "Math/Geometry/SHAABB.h" #include "Input/SHInputManager.h" #include "Editor/SHEditor.h" +#include "Scene/SHSceneManager.h" +#include "Graphics/MiddleEnd/Interface/SHDebugDrawSystem.h" +#include #include -#include +#include #include +#define DRAW_NAVIGATION_DATA +#define DRAW_NAVIGATION_PATH + + namespace SHADE { void SHNavigationSystem::Init() { + auto id = ComponentFamily::GetID(); + SHComponentManager::CreateComponentSparseSet(); SystemID i = SystemFamily::GetID(); } @@ -26,8 +35,8 @@ namespace SHADE uint16_t SHNavigationSystem::GetIndex(uint16_t row, uint16_t col) noexcept { - size_t rowOffset = numRows / sizeof(GridDataType); - return row * rowOffset + (col / sizeof(GridDataType)); + size_t rowOffset = numRows / NumGridDataTypeBits; + return row * rowOffset + (col / NumGridDataTypeBits ); } @@ -39,7 +48,7 @@ namespace SHADE GridDataType bitMask = 1 << (col % NumGridDataTypeBits); - if (navigationGrid.size() < index) + if ( index < navigationGrid.size()) { return navigationGrid[index] & bitMask; } @@ -51,7 +60,7 @@ namespace SHADE bool SHNavigationSystem::GetNavigationData(NavigationGridIndex index) noexcept { - return GetNavigationData(index.first, index.second); + return GetNavigationData(index.row, index.column); } @@ -63,14 +72,30 @@ namespace SHADE NavigationGridIndex SHNavigationSystem::GetNavigationGridIndex(SHVec3 const& worldPosition) noexcept { NavigationGridIndex result; - SHVec3 pos = worldPosition - origin; + SHVec3 topleft{ origin.x - (size.x / 2.0f), origin.y, origin.z - (size.z / 2.0f) }; + SHVec3 pos = worldPosition - topleft; SHVec2 gridSize = GetGridSize(); - result.first = pos.z / gridSize.x; - result.second = pos.x / gridSize.y; + + result.row = (pos.z )/ gridSize.y; + result.column = (pos.x )/ gridSize.x; return result; } + SHVec3 SHNavigationSystem::GetGridWorldPos(NavigationGridIndex index) noexcept + { + SHVec3 result{0.0f}; + SHVec3 topleft{ origin.x - (size.x / 2.0f), origin.y, origin.z - (size.z / 2.0f) }; + SHVec2 gridSize = GetGridSize(); + result.x = (index.column * gridSize.x); + result.z = (index.row * gridSize.y) ; + + result += topleft; + + return result; + } + + void SHNavigationSystem::GenerateNavigationGridData(SHVec3 origin, SHVec3 size, uint16_t nr, uint16_t nc) noexcept { @@ -150,12 +175,150 @@ namespace SHADE SHNavigationSystem* system = static_cast(GetSystem()); if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::H)) { - system->GenerateNavigationGridData(SHVec3{ 0.0f }, SHVec3{ 25.6f, 10.0f, 25.6f }, 128, 128); + system->GenerateNavigationGridData(SHVec3{ 0.0f }, SHVec3{ 25.6f, 1.0f, 25.6f }, 128, 128); } + + auto debugDrawSystem = SHSystemManager::GetSystem(); + if (debugDrawSystem) + { + SHTransform trans; + trans.position = SHVec3{ 0.0f }; + trans.scale = SHVec3{ 25.6f, 1.0f, 25.6f }; + trans.ComputeTRS(); + debugDrawSystem->DrawWireCube(trans.trs, SHColour::YELLOW, true); + +#ifdef DRAW_NAVIGATION_DATA + for (uint16_t r = 0; r < system->numRows; ++r) + { + for (uint16_t c = 0; c < system->numCols; ++c) + { + if (system->GetNavigationData(r, c) == true) + { + SHVec3 topleft{ system->origin.x - (system->size.x / 2.0f), system->origin.y, system->origin.z - (system->size.z / 2.0f) }; + SHVec2 halfGridSize = system->GetGridSize() * 0.5f; + + //offset it by row and column and center it with half grid size. + topleft += SHVec3{ c * system->GetGridSize().x, 0.0f, r * system->GetGridSize().y } + SHVec3{ halfGridSize.x,0.0f,halfGridSize.y }; + SHTransform t; + t.position = system->GetGridWorldPos({r,c}); + t.scale = SHVec3{ halfGridSize.x * 2.0f, 1.0f, halfGridSize.y * 2.0f}; + t.ComputeTRS(); + debugDrawSystem->DrawCube(t.trs, SHColour::RED, true); + + } + else + { + SHVec3 topleft{ system->origin.x - (system->size.x / 2.0f), system->origin.y, system->origin.z - (system->size.z / 2.0f) }; + SHVec2 halfGridSize = system->GetGridSize() * 0.5f; + + //offset it by row and column and center it with half grid size. + topleft += SHVec3{ c * system->GetGridSize().x, 0.0f, r * system->GetGridSize().y } + SHVec3{ halfGridSize.x,0.0f,halfGridSize.y }; + SHTransform t; + t.position = system->GetGridWorldPos({ r,c }); + t.scale = SHVec3{ halfGridSize.x * 2.0f, 1.0f, halfGridSize.y * 2.0f }; + t.ComputeTRS(); + debugDrawSystem->DrawCube(t.trs, SHColour::WHITE, true); + } + + + } + } +#endif + + + } + } #endif } + void SHNavigationSystem::UpdateNavigationRoutine::Execute(double dt) noexcept + { + SHNavigationSystem* system = static_cast(GetSystem()); + auto& dense = SHComponentManager::GetDense(); + + for (auto& comp : dense) + { + if (SHSceneManager::CheckNodeAndComponentsActive(comp.GetEID())) + { + if (comp.recalculatePath) + system->GeneratePath(comp); + + system->UpdateNavigationComponent(comp); + } + } + + } + + + void SHNavigationSystem::UpdateNavigationComponent(SHNavigationComponent& comp) noexcept + { + + if (comp.unreachableTarget == true || comp.path.empty()) + { + comp.forward = SHVec3::Zero; + return; // no point continuing because target can't be reached / path is empty. + } + + + SHTransformComponent* transform = SHComponentManager::GetComponent_s(comp.GetEID()); + if (transform) + { + NavigationGridIndex nxtPoint = comp.path.front(); + SHVec3 nxtPointPos = GetGridWorldPos(nxtPoint); + + SHVec3 direction = nxtPointPos - transform->GetWorldPosition(); + direction.y = 0.0f; + + + + if (direction.LengthSquared() <= comp.threshold * comp.threshold || direction.LengthSquared() <= GetGridSize().LengthSquared() * 0.5f) + { + comp.path.pop(); + //Rerun this function + UpdateNavigationComponent(comp); + //return so we don't run the parts after this twice. + return; + } + + + comp.forward = SHVec3::Normalise(direction); + +#ifdef DRAW_NAVIGATION_PATH + + auto debugDrawSystem = SHSystemManager::GetSystem(); + + auto queue = comp.path; + + while (!queue.empty()) + { + uint16_t r = queue.front().row; + uint16_t c = queue.front().column; + + { + SHVec3 topleft{ origin.x - (size.x / 2.0f), origin.y, origin.z - (size.z / 2.0f) }; + SHVec2 halfGridSize = GetGridSize() * 0.5f; + + //offset it by row and column and center it with half grid size. + topleft += SHVec3{ c * GetGridSize().x, 0.0f, r * GetGridSize().y } + SHVec3{ halfGridSize.x,0.0f,halfGridSize.y }; + SHTransform t; + t.position = GetGridWorldPos({ r,c }); + t.scale = SHVec3{ halfGridSize.x * 2.0f, 1.0f, halfGridSize.y * 2.0f }; + t.ComputeTRS(); + debugDrawSystem->DrawCube(t.trs, SHColour::YELLOW, true); + + } + queue.pop(); + } + +#endif + + } + + + } + + void SHNavigationSystem::GeneratePath(SHNavigationComponent& comp) noexcept { @@ -167,7 +330,10 @@ namespace SHADE return; } std::list openList; - std::unordered_map closedList; + std::map closedList; + closedList.clear(); + + NavigationGridIndex::numColumns = numCols; //Check if ending position is set to true in navigation data. NavigationGridIndex endIndex = GetNavigationGridIndex(comp.target); @@ -184,8 +350,8 @@ namespace SHADE NavigationNode startingNode; startingNode.index = GetNavigationGridIndex(transform->GetWorldPosition()); - startingNode.parent.first = NullGridIndex; - startingNode.parent.second = NullGridIndex; + startingNode.parent.row = NullGridIndex; + startingNode.parent.column = NullGridIndex; startingNode.h = 0; startingNode.g = 0; startingNode.f = 0; @@ -194,8 +360,8 @@ namespace SHADE NavigationNode endNode; - endNode.index.first = NullGridIndex; - endNode.index.second = NullGridIndex; + endNode.index.row = NullGridIndex; + endNode.index.column = NullGridIndex; endNode.g = std::numeric_limits::max(); endNode.h = std::numeric_limits::max(); endNode.f = std::numeric_limits::max(); @@ -235,11 +401,11 @@ namespace SHADE //Add the surrounding 8 tiles into the open list { //Top - if (currNode.index.second > 0) + if (currNode.index.column > 0) { NavigationNode topNode; topNode.index = currNode.index; - topNode.index.second -= 1; + topNode.index.column -= 1; topNode.parent = currNode.index; topNode.g = currNode.g + 10; topNode.h = HCostCalculation(topNode.index, endIndex); @@ -247,12 +413,12 @@ namespace SHADE AddNodeToOpenList(topNode, openList, closedList); //TopLeft - if (currNode.index.first > 0) + if (currNode.index.row > 0) { NavigationNode newNode; newNode.index = currNode.index; - newNode.index.second -= 1; - newNode.index.first -= 1; + newNode.index.column -= 1; + newNode.index.row -= 1; newNode.parent = currNode.index; newNode.g = currNode.g + 14; newNode.h = HCostCalculation(newNode.index, endIndex); @@ -262,11 +428,11 @@ namespace SHADE } //Bottom - if (currNode.index.second < numRows - 1) + if (currNode.index.column < numCols - 1) { NavigationNode btmNode; btmNode.index = currNode.index; - btmNode.index.second += 1; + btmNode.index.column += 1; btmNode.parent = currNode.index; btmNode.g = currNode.g + 10; btmNode.h = HCostCalculation(btmNode.index, endIndex); @@ -274,12 +440,12 @@ namespace SHADE AddNodeToOpenList(btmNode, openList, closedList); //BottomRight - if (currNode.index.first < numCols - 1) + if (currNode.index.row < numRows - 1) { NavigationNode newNode; newNode.index = currNode.index; - newNode.index.second += 1; - newNode.index.first += 1; + newNode.index.column += 1; + newNode.index.row += 1; newNode.parent = currNode.index; newNode.g = currNode.g + 14; newNode.h = HCostCalculation(newNode.index, endIndex); @@ -289,11 +455,11 @@ namespace SHADE } //Left - if (currNode.index.first > 0) + if (currNode.index.row > 0) { NavigationNode leftNode; leftNode.index = currNode.index; - leftNode.index.first -= 1; + leftNode.index.row -= 1; leftNode.parent = currNode.index; leftNode.g = currNode.g + 10; leftNode.h = HCostCalculation(leftNode.index, endIndex); @@ -302,12 +468,12 @@ namespace SHADE //BottomLeft - if (currNode.index.second < numRows - 1) + if (currNode.index.column < numCols - 1) { NavigationNode newNode; newNode.index = currNode.index; - newNode.index.second += 1; - newNode.index.first -= 1; + newNode.index.column += 1; + newNode.index.row -= 1; newNode.parent = currNode.index; newNode.g = currNode.g + 14; newNode.h = HCostCalculation(newNode.index, endIndex); @@ -318,11 +484,11 @@ namespace SHADE } //Right - if (currNode.index.first < numCols - 1) + if (currNode.index.row < numRows - 1) { NavigationNode rightNode; rightNode.index = currNode.index; - rightNode.index.first += 1; + rightNode.index.row += 1; rightNode.parent = currNode.index; rightNode.g = currNode.g + 10; rightNode.h = HCostCalculation(rightNode.index, endIndex); @@ -330,12 +496,12 @@ namespace SHADE AddNodeToOpenList(rightNode, openList, closedList); //TopRight - if (currNode.index.second > 0) + if (currNode.index.column > 0) { NavigationNode newNode; newNode.index = currNode.index; - newNode.index.second -= 1; - newNode.index.first += 1; + newNode.index.column -= 1; + newNode.index.row += 1; newNode.parent = currNode.index; newNode.g = currNode.g + 14; newNode.h = HCostCalculation(newNode.index, endIndex); @@ -345,10 +511,12 @@ namespace SHADE } } - } + +} //Check if there is a path. if (endNode.g == std::numeric_limits::max() || endNode.h == std::numeric_limits::max() || endNode.f == std::numeric_limits::max()) { + SHLOG_WARNING("Navigation System: End Node not found after running through algo EID: {}", comp.GetEID()) comp.unreachableTarget = true; return; } @@ -382,16 +550,12 @@ namespace SHADE comp.path.push(reversePath.top()); reversePath.pop(); } - - - - - - + comp.recalculatePath = false; + comp.unreachableTarget = false; }//End GeneratePath - bool SHNavigationSystem::AddNodeToOpenList(NavigationNode node, std::list& openList, std::unordered_map& closedList) noexcept + bool SHNavigationSystem::AddNodeToOpenList(NavigationNode node, std::list& openList, std::map& closedList) noexcept { if (closedList.find(node.index) != closedList.end()) { @@ -423,4 +587,20 @@ namespace SHADE } + uint32_t SHNavigationSystem::HCostCalculation(NavigationGridIndex first, NavigationGridIndex second) noexcept + { + uint16_t rDiff = (first.row > second.row)?first.row - second.row: second.row - first.row; + uint16_t cDiff = (first.column > second.column) ? first.column - second.column : second.column - first.column; + + if (rDiff > cDiff) + { + return (cDiff * 14) + ((rDiff - cDiff) * 10); + } + else + { + return (rDiff * 14 )+ ((cDiff - rDiff) * 10); + } + } + + } diff --git a/SHADE_Engine/src/Navigation/SHNavigationSystem.h b/SHADE_Engine/src/Navigation/SHNavigationSystem.h index 271d6b88..83273236 100644 --- a/SHADE_Engine/src/Navigation/SHNavigationSystem.h +++ b/SHADE_Engine/src/Navigation/SHNavigationSystem.h @@ -6,14 +6,15 @@ #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" -#include + #include "SH_API.h" namespace SHADE { - struct NavigationNode + + struct SH_API NavigationNode { NavigationGridIndex index; NavigationGridIndex parent; @@ -22,6 +23,7 @@ namespace SHADE uint32_t f; }; + class SH_API SHNavigationSystem final: public SHSystem { private: @@ -46,21 +48,22 @@ namespace SHADE SHVec2 GetGridSize() noexcept; uint16_t GetIndex(uint16_t row, uint16_t col) noexcept; - void GeneratePath(SHNavigationComponent& comp) noexcept; + uint32_t HCostCalculation(NavigationGridIndex first, NavigationGridIndex second) noexcept; //TO DO - bool AddNodeToOpenList(NavigationNode node, std::list& openList, std::unordered_map& closedList) noexcept; - + bool AddNodeToOpenList(NavigationNode node, std::list& openList, std::map& closedList) noexcept; + void UpdateNavigationComponent(SHNavigationComponent& comp) noexcept; + SHVec3 GetGridWorldPos(NavigationGridIndex index) noexcept; public: SHNavigationSystem() = default; virtual ~SHNavigationSystem() = default; - void Init(); - void Exit(); + virtual void Init(); + virtual void Exit(); - void SaveNavigationData() noexcept; + void GenerateNavigationGridData(SHVec3 origin, SHVec3 size, uint16_t numRow, uint16_t numCol) noexcept; - + void GeneratePath(SHNavigationComponent& comp) noexcept; bool GetNavigationData(uint16_t row, uint16_t col) noexcept; bool GetNavigationData(NavigationGridIndex index) noexcept; @@ -78,6 +81,15 @@ namespace SHADE }; friend class NavigationSystemGenerateRoutine; + class SH_API UpdateNavigationRoutine final: public SHSystemRoutine + { + public: + UpdateNavigationRoutine() : SHSystemRoutine("Update Navigation Routine", false) {}; + virtual void Execute(double dt)noexcept override final; + }; + friend class UpdateNavigationRoutine; + + }; diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 8dec9ad6..842c0c4e 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -243,6 +243,8 @@ namespace SHADE AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); + AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); AddComponentToComponentNode(components, eid); @@ -306,6 +308,9 @@ namespace SHADE AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); + + AddComponentID(componentIDList, componentsNode); + AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); AddComponentID(componentIDList, componentsNode); @@ -394,6 +399,9 @@ namespace SHADE SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); + SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); SHSerializationHelper::InitializeComponentFromNode(componentsNode, eid); diff --git a/SHADE_Managed/src/Components/Navigation.cxx b/SHADE_Managed/src/Components/Navigation.cxx new file mode 100644 index 00000000..3bc3200d --- /dev/null +++ b/SHADE_Managed/src/Components/Navigation.cxx @@ -0,0 +1,58 @@ +#include "SHpch.h" + +#include "Navigation.hxx" +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Navigation/SHNavigationSystem.h" + +namespace SHADE +{ + Navigation::Navigation(Entity entity) + :Component(entity) + { + + } + + float Navigation::Threshold::get() + { + return GetNativeComponent()->threshold; + } + + void Navigation::Threshold::set(float val) + { + GetNativeComponent()->threshold = val; + } + + Vector3 Navigation::Target::get() + { + return Convert::ToCLI(GetNativeComponent()->GetTarget()); + } + + void Navigation::Target::set(Vector3 val) + { + GetNativeComponent()->SetTarget(Convert::ToNative(val)); + } + + + Vector3 Navigation::GetForward() + { + return Convert::ToCLI(GetNativeComponent()->GetForward()); + } + + bool Navigation::GetUnreachableTarget() + { + return GetNativeComponent()->GetUnreachableTarget(); + } + + void Navigation::MoveTo(Vector3 val) + { + GetNativeComponent()->SetTarget(Convert::ToNative(val)); + auto system = SHSystemManager::GetSystem(); + if (system) + { + system->GeneratePath(*GetNativeComponent()); + } + + } + + +} diff --git a/SHADE_Managed/src/Components/Navigation.hxx b/SHADE_Managed/src/Components/Navigation.hxx new file mode 100644 index 00000000..eccf93dc --- /dev/null +++ b/SHADE_Managed/src/Components/Navigation.hxx @@ -0,0 +1,35 @@ +#pragma once + +#include "Components/Component.hxx" +#include "Math/Vector3.hxx" + +//External Dependencies +#include "Navigation/SHNavigationComponent.h" + +namespace SHADE +{ + public ref class Navigation : public Component + { + internal: + Navigation(Entity entity); + + public: + property float Threshold + { + float get(); + void set(float val); + } + property Vector3 Target + { + Vector3 get(); + void set(Vector3 val); + } + + Vector3 GetForward(); + bool GetUnreachableTarget(); + + void MoveTo(Vector3 val); + + + }; +} diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 38138be6..f29dd2ac 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -52,7 +52,7 @@ of DigiPen Institute of Technology is prohibited. #include "Components\TrajectoryRenderable.hxx" #include "Components\Animator.hxx" #include "Components\ParticleEmitter.hxx" - +#include "Components\Navigation.hxx" namespace SHADE @@ -344,6 +344,7 @@ namespace SHADE componentMap.Add(createComponentSet()); componentMap.Add(createComponentSet()); componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); } /*---------------------------------------------------------------------------------*/