From bc964f999405c6cb427a967f3afd1b29dca02a8c Mon Sep 17 00:00:00 2001 From: Mikko Mononen Date: Tue, 21 Jan 2014 19:15:03 +0200 Subject: [PATCH] Fix for U-turn path case --- RecastDemo/Source/NavMeshTesterTool.cpp | 66 ++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/RecastDemo/Source/NavMeshTesterTool.cpp b/RecastDemo/Source/NavMeshTesterTool.cpp index 146624e..3b49d4b 100644 --- a/RecastDemo/Source/NavMeshTesterTool.cpp +++ b/RecastDemo/Source/NavMeshTesterTool.cpp @@ -101,6 +101,66 @@ static int fixupCorridor(dtPolyRef* path, const int npath, const int maxPath, return req+size; } +// This function checks if the path has a small U-turn, that is, +// a polygon further in the path is adjacent to the first polygon +// in the path. If that happens, a shortcut is taken. +// This can happen if the target (T) location is at tile boundary, +// and we're (S) approaching it parallel to the tile edge. +// The choice at the vertex can be arbitrary, +// +---+---+ +// |:::|:::| +// +-S-+-T-+ +// |:::| | <-- the step can end up in here, resulting U-turn path. +// +---+---+ +static int fixupShortcuts(dtPolyRef* path, int npath, dtNavMeshQuery* navQuery) +{ + if (npath < 3) + return npath; + + // Get connected polygons + static const int maxNeis = 16; + dtPolyRef neis[maxNeis]; + int nneis = 0; + + const dtMeshTile* tile = 0; + const dtPoly* poly = 0; + if (dtStatusFailed(navQuery->getAttachedNavMesh()->getTileAndPolyByRef(path[0], &tile, &poly))) + return npath; + + for (unsigned int k = poly->firstLink; k != DT_NULL_LINK; k = tile->links[k].next) + { + const dtLink* link = &tile->links[k]; + if (link->ref != 0) + { + if (nneis < maxNeis) + neis[nneis++] = link->ref; + } + } + + // If any of the neighbour polygons is within the next few polygons + // in the path, short cut to that polygon directly. + static const int maxLookAhead = 6; + int cut = 0; + for (int i = dtMin(maxLookAhead, npath) - 1; i > 1 && cut == 0; i--) { + for (int j = 0; j < nneis; j++) + { + if (path[i] == neis[j]) { + cut = i; + break; + } + } + } + if (cut > 1) + { + int offset = cut-1; + npath -= offset; + for (int i = 1; i < npath; i++) + path[i] = path[i+offset]; + } + + return npath; +} + static bool getSteerTarget(dtNavMeshQuery* navQuery, const float* startPos, const float* endPos, const float minTargetDist, const dtPolyRef* path, const int pathSize, @@ -503,6 +563,8 @@ void NavMeshTesterTool::handleToggle() m_navQuery->moveAlongSurface(m_pathIterPolys[0], m_iterPos, moveTgt, &m_filter, result, visited, &nvisited, 16); m_pathIterPolyCount = fixupCorridor(m_pathIterPolys, m_pathIterPolyCount, MAX_POLYS, visited, nvisited); + m_pathIterPolyCount = fixupShortcuts(m_pathIterPolys, m_pathIterPolyCount, m_navQuery); + float h = 0; m_navQuery->getPolyHeight(m_pathIterPolys[0], result, &h); result[1] = h; @@ -698,8 +760,10 @@ void NavMeshTesterTool::recalc() int nvisited = 0; m_navQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &m_filter, result, visited, &nvisited, 16); - + npolys = fixupCorridor(polys, npolys, MAX_POLYS, visited, nvisited); + npolys = fixupShortcuts(polys, npolys, m_navQuery); + float h = 0; m_navQuery->getPolyHeight(polys[0], result, &h); result[1] = h;