diff --git a/Source/Engine/Navigation/NavMeshRuntime.cpp b/Source/Engine/Navigation/NavMeshRuntime.cpp index 5278730f1..e6c255782 100644 --- a/Source/Engine/Navigation/NavMeshRuntime.cpp +++ b/Source/Engine/Navigation/NavMeshRuntime.cpp @@ -4,7 +4,7 @@ #include "NavigationSettings.h" #include "NavMesh.h" #include "Engine/Core/Log.h" -#include "Engine/Core/Math/Matrix.h" +#include "Engine/Core/Random.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Threading/Threading.h" #include @@ -231,6 +231,71 @@ bool NavMeshRuntime::ProjectPoint(const Vector3& point, Vector3& result) const return true; } +bool NavMeshRuntime::FindRandomPoint(Vector3& result) const +{ + ScopeLock lock(Locker); + + const auto query = GetNavMeshQuery(); + if (!query || !_navMesh) + { + return false; + } + + dtQueryFilter filter; + InitFilter(filter); + + dtPolyRef randomPoly = 0; + query->findRandomPoint(&filter, Random::Rand, &randomPoly, &result.X); + if (!randomPoly) + { + return false; + } + + Quaternion invRotation; + Quaternion::Invert(Properties.Rotation, invRotation); + Vector3::Transform(result, invRotation, result); + + return true; +} + +bool NavMeshRuntime::FindRandomPointAroundCircle(const Vector3& center, float radius, Vector3& result) const +{ + ScopeLock lock(Locker); + + const auto query = GetNavMeshQuery(); + if (!query || !_navMesh) + { + return false; + } + + dtQueryFilter filter; + InitFilter(filter); + Vector3 extent(DEFAULT_NAV_QUERY_EXTENT_HORIZONTAL, DEFAULT_NAV_QUERY_EXTENT_VERTICAL, DEFAULT_NAV_QUERY_EXTENT_HORIZONTAL); + + Vector3 centerNavMesh; + Vector3::Transform(center, Properties.Rotation, centerNavMesh); + + dtPolyRef centerPoly = 0; + query->findNearestPoly(¢erNavMesh.X, &extent.X, &filter, ¢erPoly, nullptr); + if (!centerPoly) + { + return false; + } + + dtPolyRef randomPoly = 0; + query->findRandomPointAroundCircle(centerPoly, ¢erNavMesh.X, radius, &filter, Random::Rand, &randomPoly, &result.X); + if (!randomPoly) + { + return false; + } + + Quaternion invRotation; + Quaternion::Invert(Properties.Rotation, invRotation); + Vector3::Transform(result, invRotation, result); + + return true; +} + bool NavMeshRuntime::RayCast(const Vector3& startPosition, const Vector3& endPosition, NavMeshHit& hitInfo) const { ScopeLock lock(Locker); @@ -522,6 +587,7 @@ void NavMeshRuntime::RemoveTiles(bool (* prediction)(const NavMeshRuntime* navMe #if COMPILE_WITH_DEBUG_DRAW #include "Engine/Debug/DebugDraw.h" +#include "Engine/Core/Math/Matrix.h" void DrawPoly(NavMeshRuntime* navMesh, const Matrix& navMeshToWorld, const dtMeshTile& tile, const dtPoly& poly) { diff --git a/Source/Engine/Navigation/NavMeshRuntime.h b/Source/Engine/Navigation/NavMeshRuntime.h index fd8dcf794..08f6c7744 100644 --- a/Source/Engine/Navigation/NavMeshRuntime.h +++ b/Source/Engine/Navigation/NavMeshRuntime.h @@ -127,6 +127,22 @@ public: /// True if found valid location on the navmesh, otherwise false. bool ProjectPoint(const Vector3& point, Vector3& result) const; + /// + /// Finds random location on nav mesh. + /// + /// The result position on the navmesh (valid only if method returns true). + /// True if found valid location on the navmesh, otherwise false. + bool FindRandomPoint(Vector3& result) const; + + /// + /// Finds random location on nav mesh within the reach of specified location. + /// + /// The source point to find random location around it. + /// The search distance for a random point. Maximum distance for a result point from the center of the circle. + /// The result position on the navmesh (valid only if method returns true). + /// True if found valid location on the navmesh, otherwise false. + bool FindRandomPointAroundCircle(const Vector3& center, float radius, Vector3& result) const; + /// /// Casts a 'walkability' ray along the surface of the navigation mesh from the start position toward the end position. /// diff --git a/Source/Engine/Navigation/Navigation.cpp b/Source/Engine/Navigation/Navigation.cpp index 9ff3498d7..db9c95089 100644 --- a/Source/Engine/Navigation/Navigation.cpp +++ b/Source/Engine/Navigation/Navigation.cpp @@ -315,6 +315,20 @@ bool Navigation::ProjectPoint(const Vector3& point, Vector3& result) return NavMeshes.First()->ProjectPoint(point, result); } +bool Navigation::FindRandomPoint(Vector3& result) +{ + if (NavMeshes.IsEmpty()) + return false; + return NavMeshes.First()->FindRandomPoint(result); +} + +bool Navigation::FindRandomPointAroundCircle(const Vector3& center, float radius, Vector3& result) +{ + if (NavMeshes.IsEmpty()) + return false; + return NavMeshes.First()->FindRandomPointAroundCircle(center, radius, result); +} + bool Navigation::RayCast(const Vector3& startPosition, const Vector3& endPosition, NavMeshHit& hitInfo) { if (NavMeshes.IsEmpty()) diff --git a/Source/Engine/Navigation/Navigation.h b/Source/Engine/Navigation/Navigation.h index dcd6b9fbb..3941af958 100644 --- a/Source/Engine/Navigation/Navigation.h +++ b/Source/Engine/Navigation/Navigation.h @@ -48,6 +48,23 @@ public: /// True if found valid location on the navmesh, otherwise false. API_FUNCTION() static bool ProjectPoint(const Vector3& point, API_PARAM(Out) Vector3& result); + /// + /// Finds random location on nav mesh. + /// + /// The result position on the navmesh (valid only if method returns true). + /// True if found valid location on the navmesh, otherwise false. + API_FUNCTION() static bool FindRandomPoint(API_PARAM(Out) Vector3& result); + + /// + /// Finds random location on nav mesh within the reach of specified location. + /// + /// If the result location doesn't need to be exactly inside the circle but just in local are aof the navigation mesh polys, then use more optimized . + /// The source point to find random location around it. + /// The search distance for a random point. Maximum distance for a result point from the center of the circle. + /// The result position on the navmesh (valid only if method returns true). + /// True if found valid location on the navmesh, otherwise false. + API_FUNCTION() static bool FindRandomPointAroundCircle(const Vector3& center, float radius, API_PARAM(Out) Vector3& result); + /// /// Casts a 'walkability' ray along the surface of the navigation mesh from the start position toward the end position. ///