// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Types/BaseTypes.h" #include "Engine/Platform/CriticalSection.h" #include "Engine/Scripting/ScriptingObject.h" #include "NavMeshData.h" #include "NavigationTypes.h" class dtNavMesh; class dtNavMeshQuery; class NavMesh; /// /// The navigation mesh tile data. /// class FLAXENGINE_API NavMeshTile { public: int32 X; int32 Y; int32 Layer; NavMesh* NavMesh; BytesContainer Data; }; /// /// The navigation mesh path flags. /// enum class NavMeshPathFlags { // Nothing. None = 0, // Path is only partially generated, goal is unreachable so path represents the best guess. PartialPath = 1, }; DECLARE_ENUM_OPERATORS(NavMeshPathFlags); /// /// The navigation mesh runtime object that builds the navmesh from all loaded scenes. /// API_CLASS(NoSpawn) class FLAXENGINE_API NavMeshRuntime : public ScriptingObject { DECLARE_SCRIPTING_TYPE_MINIMAL(NavMeshRuntime); public: // Gets the first valid navigation mesh runtime. Return null if none created. API_FUNCTION() static NavMeshRuntime* Get(); // Gets the navigation mesh runtime for a given navmesh name. Return null if missing. API_FUNCTION() static NavMeshRuntime* Get(const StringView& navMeshName); // Gets the navigation mesh runtime for a given agent properties trying to pick the best matching navmesh. API_FUNCTION() static NavMeshRuntime* Get(API_PARAM(Ref) const NavAgentProperties& agentProperties); // Gets the navigation mesh runtime for a given navmesh properties. API_FUNCTION() static NavMeshRuntime* Get(API_PARAM(Ref) const NavMeshProperties& navMeshProperties, bool createIfMissing = false); // The lookup table that maps areaId of the navmesh to the current properties (applied by the NavigationSettings). Cached to improve runtime performance. static float NavAreasCosts[64]; #if COMPILE_WITH_DEBUG_DRAW static Color NavAreasColors[64]; #endif private: dtNavMesh* _navMesh; dtNavMeshQuery* _navMeshQuery; float _tileSize; Array _tiles; public: NavMeshRuntime(const NavMeshProperties& properties); ~NavMeshRuntime(); public: /// /// The object locker. /// CriticalSection Locker; /// /// The navigation mesh properties. /// API_FIELD(ReadOnly) NavMeshProperties Properties; /// /// Gets the size of the tile (in world-units). Returns zero if not initialized yet. /// API_PROPERTY() FORCE_INLINE float GetTileSize() const { return _tileSize; } dtNavMesh* GetNavMesh() const { return _navMesh; } dtNavMeshQuery* GetNavMeshQuery() const { return _navMeshQuery; } int32 GetTilesCapacity() const; public: /// /// Finds the distance from the specified start position to the nearest polygon wall. /// /// The start position. /// The result hit information. Valid only when query succeed. /// The maximum distance to search for wall (search radius). /// True if ray hits an matching object, otherwise false. API_FUNCTION() bool FindDistanceToWall(const Vector3& startPosition, NavMeshHit& hitInfo, float maxDistance = MAX_float) const; /// /// Finds the path between the two positions presented as a list of waypoints stored in the corners array. /// /// The start position. /// The end position. /// The result path. /// True if found valid path between given two points (it may be partial), otherwise false if failed. API_FUNCTION() bool FindPath(const Vector3& startPosition, const Vector3& endPosition, API_PARAM(Out) Array& resultPath) const { NavMeshPathFlags flags; return FindPath(startPosition, endPosition, resultPath, flags); } /// /// Finds the path between the two positions presented as a list of waypoints stored in the corners array. /// /// The start position. /// The end position. /// The result path. /// The result path flags. /// True if found valid path between given two points (it may be partial), otherwise false if failed. bool FindPath(const Vector3& startPosition, const Vector3& endPosition, API_PARAM(Out) Array& resultPath, NavMeshPathFlags& resultFlags) const; /// /// Tests the path between the two positions (non-partial). /// /// The start position. /// The end position. /// True if found valid path between given two points, otherwise false if failed. API_FUNCTION() bool TestPath(const Vector3& startPosition, const Vector3& endPosition) const; /// /// Projects the point to nav mesh surface (finds the nearest polygon). /// /// The source point. /// The result position on the navmesh (valid only if method returns true). /// True if found valid location on the navmesh, otherwise false. API_FUNCTION() bool ProjectPoint(const Vector3& point, API_PARAM(Out) 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. API_FUNCTION() bool FindRandomPoint(API_PARAM(Out) 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. API_FUNCTION() bool FindRandomPointAroundCircle(const Vector3& center, float radius, API_PARAM(Out) Vector3& result) const; /// /// Casts a 'walkability' ray along the surface of the navigation mesh from the start position toward the end position. /// /// The start position. /// The end position. /// The result hit information. Valid only when query succeed. /// True if ray hits an matching object, otherwise false. API_FUNCTION() bool RayCast(const Vector3& startPosition, const Vector3& endPosition, API_PARAM(Out) NavMeshHit& hitInfo) const; public: /// /// Sets the size of the tile (if not assigned). Disposes the mesh if added tiles have different size. /// /// The size of the tile. void SetTileSize(float tileSize); /// /// Ensures the navmesh capacity for adding new tiles. Performs resizing if needed. /// /// The new tiles amount. void EnsureCapacity(int32 tilesToAddCount); /// /// Adds the tiles from the given scene to the runtime navmesh. /// /// The navigation mesh. void AddTiles(NavMesh* navMesh); /// /// Adds the tile from the given scene to the runtime navmesh. /// /// The navigation mesh. /// The tile data. void AddTile(NavMesh* navMesh, NavMeshTileData& tileData); /// /// Removes all the tiles from the navmesh that has been added from the given navigation scene. /// /// The navigation mesh. void RemoveTiles(NavMesh* navMesh); /// /// Removes the tile from the navmesh. /// /// The tile X coordinate. /// The tile Y coordinate. /// The tile layer. void RemoveTile(int32 x, int32 y, int32 layer); /// /// Removes all the tiles that custom prediction callback marks. /// /// The prediction callback, returns true for tiles to remove and false for tiles to preserve. /// The user data passed to the callback method. void RemoveTiles(bool (*prediction)(const NavMeshRuntime* navMesh, const NavMeshTile& tile, void* customData), void* userData); #if COMPILE_WITH_DEBUG_DRAW void DebugDraw(); #endif /// /// Releases the navmesh. /// void Dispose(); private: void AddTileInternal(NavMesh* navMesh, NavMeshTileData& tileData); };