1
0

Pathfinder - approximated paths when original destination unreachable

This commit is contained in:
SafwatHalaby
2015-05-16 14:05:33 +03:00
parent 4ffc6621a9
commit 29e31c5be9
5 changed files with 193 additions and 55 deletions

View File

@@ -8,7 +8,7 @@
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
#define CALCULATIONS_PER_STEP 5 // Higher means more CPU load but faster path calculations.
#define CALCULATIONS_PER_STEP 10 // Higher means more CPU load but faster path calculations.
// The only version which guarantees the shortest path is 0, 0.
enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST};
@@ -44,7 +44,8 @@ cPath::cPath(
m_Destination(a_EndingPoint.Floor()),
m_Source(a_StartingPoint.Floor()),
m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
m_Chunk(&a_Chunk)
m_Chunk(&a_Chunk),
m_BadChunkFound(false)
{
// TODO: if src not walkable OR dest not walkable, then abort.
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
@@ -55,6 +56,7 @@ cPath::cPath(
return;
}
m_NearestPointToTarget = GetCell(m_Source);
m_Status = ePathFinderStatus::CALCULATING;
m_StepsLeft = a_MaxSteps;
@@ -81,15 +83,20 @@ cPath::~cPath()
ePathFinderStatus cPath::Step(cChunk & a_Chunk)
{
m_Chunk = &a_Chunk;
if (m_Status != ePathFinderStatus::CALCULATING)
{
return m_Status;
}
if (m_StepsLeft == 0)
if (m_BadChunkFound)
{
FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
return m_Status;
}
if (m_StepsLeft == 0)
{
AttemptToFindAlternative();
}
else
{
@@ -102,9 +109,9 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
break; // if we're here, m_Status must have changed either to PATH_FOUND or PATH_NOT_FOUND.
}
}
}
m_Chunk = nullptr;
m_Chunk = nullptr;
}
return m_Status;
}
@@ -112,6 +119,17 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
Vector3i cPath::AcceptNearbyPath()
{
ASSERT(m_Status == ePathFinderStatus::NEARBY_FOUND);
m_Status = ePathFinderStatus::PATH_FOUND;
return m_Destination;
}
bool cPath::IsSolid(const Vector3i & a_Location)
{
ASSERT(m_Chunk != nullptr);
@@ -119,6 +137,7 @@ bool cPath::IsSolid(const Vector3i & a_Location)
auto Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
if ((Chunk == nullptr) || !Chunk->IsValid())
{
m_BadChunkFound = true;
return true;
}
m_Chunk = Chunk;
@@ -149,34 +168,29 @@ bool cPath::Step_Internal()
{
cPathCell * CurrentCell = OpenListPop();
// Path not reachable, open list exauhsted.
// Path not reachable.
if (CurrentCell == nullptr)
{
FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
ASSERT(m_Status == ePathFinderStatus::PATH_NOT_FOUND);
AttemptToFindAlternative();
return true;
}
// Path found.
if (
(CurrentCell->m_Location == m_Destination + Vector3i(0, 0, 1)) ||
(CurrentCell->m_Location == m_Destination + Vector3i(1, 0, 0)) ||
(CurrentCell->m_Location == m_Destination + Vector3i(-1, 0, 0)) ||
(CurrentCell->m_Location == m_Destination + Vector3i(0, 0, -1)) ||
(CurrentCell->m_Location == m_Destination + Vector3i(0, -1, 0))
)
if (CurrentCell->m_Location == m_Destination)
{
do
{
m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points.
CurrentCell = CurrentCell->m_Parent;
} while (CurrentCell != nullptr);
BuildPath();
FinishCalculation(ePathFinderStatus::PATH_FOUND);
return true;
}
// Calculation not finished yet, process a currentCell by inspecting all neighbors.
// Calculation not finished yet.
// Check if we have a new NearestPoint.
if (CurrentCell->m_H < m_NearestPointToTarget->m_H)
{
m_NearestPointToTarget = CurrentCell;
}
// process a currentCell by inspecting all neighbors.
// Check North, South, East, West on all 3 different heights.
int i;
@@ -213,6 +227,38 @@ bool cPath::Step_Internal()
void cPath::AttemptToFindAlternative()
{
if (m_NearestPointToTarget == GetCell(m_Source))
{
FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
}
else
{
m_Destination = m_NearestPointToTarget->m_Location;
BuildPath();
FinishCalculation(ePathFinderStatus::NEARBY_FOUND);
}
}
void cPath::BuildPath()
{
cPathCell * CurrentCell = GetCell(m_Destination);
do
{
m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points.
CurrentCell = CurrentCell->m_Parent;
} while (CurrentCell != nullptr);
}
void cPath::FinishCalculation()
{
m_Map.clear();
@@ -225,6 +271,10 @@ void cPath::FinishCalculation()
void cPath::FinishCalculation(ePathFinderStatus a_NewStatus)
{
if (m_BadChunkFound)
{
a_NewStatus = ePathFinderStatus::PATH_NOT_FOUND;
}
m_Status = a_NewStatus;
FinishCalculation();
}
@@ -250,7 +300,7 @@ cPathCell * cPath::OpenListPop() // Popping from the open list also means addin
{
if (m_OpenList.size() == 0)
{
return nullptr; // We've exhausted the search space and nothing was found, this will trigger a PATH_NOT_FOUND status.
return nullptr; // We've exhausted the search space and nothing was found, this will trigger a PATH_NOT_FOUND or NEARBY_FOUND status.
}
cPathCell * Ret = m_OpenList.top();