| 92 | } |
| 93 | |
| 94 | bool NavMeshRuntime::FindPath(const Vector3& startPosition, const Vector3& endPosition, Array<Vector3, HeapAllocation>& resultPath, NavMeshPathFlags& resultFlags) const |
| 95 | { |
| 96 | resultPath.Clear(); |
| 97 | resultFlags = NavMeshPathFlags::None; |
| 98 | ScopeLock lock(Locker); |
| 99 | const auto query = GetNavMeshQuery(); |
| 100 | if (!query || !_navMesh) |
| 101 | return false; |
| 102 | |
| 103 | dtQueryFilter filter; |
| 104 | InitFilter(filter); |
| 105 | Float3 extent = Properties.DefaultQueryExtent; |
| 106 | |
| 107 | Float3 startPositionNavMesh, endPositionNavMesh; |
| 108 | Float3::Transform(startPosition, Properties.Rotation, startPositionNavMesh); |
| 109 | Float3::Transform(endPosition, Properties.Rotation, endPositionNavMesh); |
| 110 | |
| 111 | dtPolyRef startPoly = 0; |
| 112 | if (!dtStatusSucceed(query->findNearestPoly(&startPositionNavMesh.X, &extent.X, &filter, &startPoly, nullptr))) |
| 113 | return false; |
| 114 | dtPolyRef endPoly = 0; |
| 115 | if (!dtStatusSucceed(query->findNearestPoly(&endPositionNavMesh.X, &extent.X, &filter, &endPoly, nullptr))) |
| 116 | return false; |
| 117 | |
| 118 | dtPolyRef path[NAV_MESH_PATH_MAX_SIZE]; |
| 119 | int32 pathSize; |
| 120 | const auto findPathStatus = query->findPath(startPoly, endPoly, &startPositionNavMesh.X, &endPositionNavMesh.X, &filter, path, &pathSize, NAV_MESH_PATH_MAX_SIZE); |
| 121 | if (dtStatusFailed(findPathStatus)) |
| 122 | { |
| 123 | return false; |
| 124 | } |
| 125 | |
| 126 | Quaternion invRotation; |
| 127 | Quaternion::Invert(Properties.Rotation, invRotation); |
| 128 | |
| 129 | if (pathSize == 1 && dtStatusDetail(findPathStatus, DT_PARTIAL_RESULT)) |
| 130 | { |
| 131 | resultFlags |= NavMeshPathFlags::PartialPath; |
| 132 | // TODO: skip adding 2nd end point if it's not reachable (use navmesh raycast check? or physics check? or local Z distance check?) |
| 133 | resultPath.Resize(2); |
| 134 | resultPath[0] = startPosition; |
| 135 | query->closestPointOnPolyBoundary(startPoly, &endPositionNavMesh.X, &endPositionNavMesh.X); |
| 136 | resultPath[1] = endPositionNavMesh; |
| 137 | Vector3::Transform(resultPath[1], invRotation, resultPath[1]); |
| 138 | } |
| 139 | else |
| 140 | { |
| 141 | int pathPointsCount = 0; |
| 142 | Float3 pathPoints[NAV_MESH_PATH_MAX_SIZE]; |
| 143 | const auto findStraightPathStatus = query->findStraightPath(&startPositionNavMesh.X, &endPositionNavMesh.X, path, pathSize, (float*)&pathPoints, nullptr, nullptr, &pathPointsCount, NAV_MESH_PATH_MAX_SIZE, DT_STRAIGHTPATH_AREA_CROSSINGS); |
| 144 | if (dtStatusFailed(findStraightPathStatus)) |
| 145 | { |
| 146 | return false; |
| 147 | } |
| 148 | resultPath.Resize(pathPointsCount); |
| 149 | for (int32 i = 0; i < pathPointsCount; i++) |
| 150 | { |
| 151 | Vector3::Transform(pathPoints[i], invRotation, resultPath[i]); |
nothing calls this directly
no test coverage detected