Fix a number of short/long range pathfinder inconsistencies revealed by 128a603287
.
This was SVN commit r16869.
This commit is contained in:
parent
1e79b3a8af
commit
f240374b28
@ -790,6 +790,22 @@ void CCmpPathfinder::ProcessSameTurnMoves()
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
bool CCmpPathfinder::CheckMovement(const IObstructionTestFilter& filter,
|
||||
entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r,
|
||||
pass_class_t passClass)
|
||||
{
|
||||
// Test against obstructions first
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());
|
||||
if (!cmpObstructionManager)
|
||||
return false;
|
||||
|
||||
if (cmpObstructionManager->TestLine(filter, x0, z0, x1, z1, r))
|
||||
return false;
|
||||
|
||||
// Then test against the terrain
|
||||
return Pathfinding::CheckLineMovement(x0, z0, x1, z1, passClass, *m_TerrainOnlyGrid);
|
||||
}
|
||||
|
||||
ICmpObstruction::EFoundationCheck CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter,
|
||||
entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass, bool UNUSED(onlyCenterPoint))
|
||||
{
|
||||
|
@ -293,7 +293,7 @@ typedef PriorityQueueHeap<u16, fixed, fixed> VertexPriorityQueue;
|
||||
|
||||
/**
|
||||
* Add edges and vertexes to represent the boundaries between passable and impassable
|
||||
* navcells (for impassable terrain and for static obstruction shapes).
|
||||
* navcells (for impassable terrain).
|
||||
* Navcells i0 <= i <= i1, j0 <= j <= j1 will be considered.
|
||||
*/
|
||||
static void AddTerrainEdges(std::vector<Edge>& edges, std::vector<Vertex>& vertexes,
|
||||
@ -938,21 +938,3 @@ void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,
|
||||
|
||||
PROFILE_END("Short pathfinding - A*");
|
||||
}
|
||||
|
||||
bool CCmpPathfinder::CheckMovement(const IObstructionTestFilter& filter,
|
||||
entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r,
|
||||
pass_class_t passClass)
|
||||
{
|
||||
// Test against dynamic obstructions first
|
||||
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());
|
||||
if (!cmpObstructionManager)
|
||||
return false;
|
||||
|
||||
if (cmpObstructionManager->TestLine(filter, x0, z0, x1, z1, r))
|
||||
return false;
|
||||
|
||||
// Test against the passability grid.
|
||||
// This ignores r.
|
||||
return m_LongPathfinder.CheckLineMovement(x0, z0, x1, z1, passClass);
|
||||
}
|
||||
|
@ -346,12 +346,6 @@ public:
|
||||
if (group == m_Group || (group2 != INVALID_ENTITY && group2 == m_Group))
|
||||
return false;
|
||||
|
||||
// If an obstruction already blocks tile-based pathfinding,
|
||||
// it will be handled as part of the terrain passability handling
|
||||
// and doesn't need to be matched by this filter
|
||||
if (flags & ICmpObstructionManager::FLAG_BLOCK_PATHFINDING)
|
||||
return false;
|
||||
|
||||
if (!(flags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT))
|
||||
return false;
|
||||
|
||||
|
@ -1070,7 +1070,7 @@ void LongPathfinder::ImprovePathWaypoints(WaypointPath& path, pass_class_t passC
|
||||
if ((ahead - curr).Perpendicular().Dot(curr - prev).Absolute() <= fixed::Epsilon() * 100)
|
||||
continue;
|
||||
|
||||
if (!CheckLineMovement(prev.X, prev.Y, ahead.X, ahead.Y, passClass))
|
||||
if (!Pathfinding::CheckLineMovement(prev.X, prev.Y, ahead.X, ahead.Y, passClass, *m_Grid))
|
||||
{
|
||||
prev = CFixedVector2D(waypoints[k].x, waypoints[k].z);
|
||||
newWaypoints.push_back(waypoints[k]);
|
||||
@ -1080,88 +1080,6 @@ void LongPathfinder::ImprovePathWaypoints(WaypointPath& path, pass_class_t passC
|
||||
path.m_Waypoints.swap(newWaypoints);
|
||||
}
|
||||
|
||||
bool LongPathfinder::CheckLineMovement(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, pass_class_t passClass)
|
||||
{
|
||||
// We shouldn't allow lines between diagonally-adjacent navcells.
|
||||
// It doesn't matter whether we allow lines precisely along the edge
|
||||
// of an impassable navcell.
|
||||
|
||||
// To rasterise the line:
|
||||
// If the line is (e.g.) aiming up-right, then we start at the navcell
|
||||
// containing the start point and the line must either end in that navcell
|
||||
// or else exit along the top edge or the right edge (or through the top-right corner,
|
||||
// which we'll arbitrary treat as the horizontal edge).
|
||||
// So we jump into the adjacent navcell across that edge, and continue.
|
||||
|
||||
// To handle the special case of units that are stuck on impassable cells,
|
||||
// we allow them to move from an impassable to a passable cell (but not
|
||||
// vice versa).
|
||||
|
||||
u16 i0, j0, i1, j1;
|
||||
Pathfinding::NearestNavcell(x0, z0, i0, j0, m_GridSize, m_GridSize);
|
||||
Pathfinding::NearestNavcell(x1, z1, i1, j1, m_GridSize, m_GridSize);
|
||||
|
||||
// Find which direction the line heads in
|
||||
int di = (i0 < i1 ? +1 : i1 < i0 ? -1 : 0);
|
||||
int dj = (j0 < j1 ? +1 : j1 < j0 ? -1 : 0);
|
||||
|
||||
u16 i = i0;
|
||||
u16 j = j0;
|
||||
|
||||
bool currentlyOnImpassable = !IS_PASSABLE(m_Grid->get(i0, j0), passClass);
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Fail if we're moving onto an impassable navcell
|
||||
bool passable = IS_PASSABLE(m_Grid->get(i, j), passClass);
|
||||
if (passable)
|
||||
currentlyOnImpassable = false;
|
||||
else if (!currentlyOnImpassable)
|
||||
return false;
|
||||
|
||||
// Succeed if we're at the target
|
||||
if (i == i1 && j == j1)
|
||||
return true;
|
||||
|
||||
// If we can only move horizontally/vertically, then just move in that direction
|
||||
if (di == 0)
|
||||
{
|
||||
j += dj;
|
||||
continue;
|
||||
}
|
||||
else if (dj == 0)
|
||||
{
|
||||
i += di;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise we need to check which cell to move into:
|
||||
|
||||
// Check whether the line intersects the horizontal (top/bottom) edge of
|
||||
// the current navcell.
|
||||
// Horizontal edge is (i, j + (dj>0?1:0)) .. (i + 1, j + (dj>0?1:0))
|
||||
// Since we already know the line is moving from this navcell into a different
|
||||
// navcell, we simply need to test that the edge's endpoints are not both on the
|
||||
// same side of the line.
|
||||
|
||||
entity_pos_t xia = entity_pos_t::FromInt(i).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t xib = entity_pos_t::FromInt(i+1).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t zj = entity_pos_t::FromInt(j + (dj+1)/2).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
|
||||
CFixedVector2D perp = CFixedVector2D(x1 - x0, z1 - z0).Perpendicular();
|
||||
entity_pos_t dota = (CFixedVector2D(xia, zj) - CFixedVector2D(x0, z0)).Dot(perp);
|
||||
entity_pos_t dotb = (CFixedVector2D(xib, zj) - CFixedVector2D(x0, z0)).Dot(perp);
|
||||
|
||||
// If the horizontal edge is fully on one side of the line, so the line doesn't
|
||||
// intersect it, we should move across the vertical edge instead
|
||||
if ((dota < entity_pos_t::Zero() && dotb < entity_pos_t::Zero()) ||
|
||||
(dota > entity_pos_t::Zero() && dotb > entity_pos_t::Zero()))
|
||||
i += di;
|
||||
else
|
||||
j += dj;
|
||||
}
|
||||
}
|
||||
|
||||
void LongPathfinder::GetDebugDataJPS(u32& steps, double& time, Grid<u8>& grid)
|
||||
{
|
||||
steps = m_DebugSteps;
|
||||
|
@ -249,11 +249,6 @@ public:
|
||||
GetDebugDataJPS(steps, time, grid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that the line (x0,z0)-(x1,z1) does not intersect any impassable navcells.
|
||||
*/
|
||||
bool CheckLineMovement(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, pass_class_t passClass);
|
||||
|
||||
Grid<NavcellData>* m_Grid;
|
||||
u16 m_GridSize;
|
||||
|
||||
|
@ -148,6 +148,92 @@ namespace Pathfinding
|
||||
x = entity_pos_t::FromInt(i * 2 + 1).Multiply(NAVCELL_SIZE / 2);
|
||||
z = entity_pos_t::FromInt(j * 2 + 1).Multiply(NAVCELL_SIZE / 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that the line (x0,z0)-(x1,z1) does not intersect any impassable navcells.
|
||||
*/
|
||||
inline bool CheckLineMovement(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1,
|
||||
pass_class_t passClass, const Grid<NavcellData>& grid)
|
||||
{
|
||||
// We shouldn't allow lines between diagonally-adjacent navcells.
|
||||
// It doesn't matter whether we allow lines precisely along the edge
|
||||
// of an impassable navcell.
|
||||
|
||||
// To rasterise the line:
|
||||
// If the line is (e.g.) aiming up-right, then we start at the navcell
|
||||
// containing the start point and the line must either end in that navcell
|
||||
// or else exit along the top edge or the right edge (or through the top-right corner,
|
||||
// which we'll arbitrary treat as the horizontal edge).
|
||||
// So we jump into the adjacent navcell across that edge, and continue.
|
||||
|
||||
// To handle the special case of units that are stuck on impassable cells,
|
||||
// we allow them to move from an impassable to a passable cell (but not
|
||||
// vice versa).
|
||||
|
||||
u16 i0, j0, i1, j1;
|
||||
Pathfinding::NearestNavcell(x0, z0, i0, j0, grid.m_W, grid.m_H);
|
||||
Pathfinding::NearestNavcell(x1, z1, i1, j1, grid.m_W, grid.m_H);
|
||||
|
||||
// Find which direction the line heads in
|
||||
int di = (i0 < i1 ? +1 : i1 < i0 ? -1 : 0);
|
||||
int dj = (j0 < j1 ? +1 : j1 < j0 ? -1 : 0);
|
||||
|
||||
u16 i = i0;
|
||||
u16 j = j0;
|
||||
|
||||
bool currentlyOnImpassable = !IS_PASSABLE(grid.get(i0, j0), passClass);
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Fail if we're moving onto an impassable navcell
|
||||
bool passable = IS_PASSABLE(grid.get(i, j), passClass);
|
||||
if (passable)
|
||||
currentlyOnImpassable = false;
|
||||
else if (!currentlyOnImpassable)
|
||||
return false;
|
||||
|
||||
// Succeed if we're at the target
|
||||
if (i == i1 && j == j1)
|
||||
return true;
|
||||
|
||||
// If we can only move horizontally/vertically, then just move in that direction
|
||||
if (di == 0)
|
||||
{
|
||||
j += dj;
|
||||
continue;
|
||||
}
|
||||
else if (dj == 0)
|
||||
{
|
||||
i += di;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise we need to check which cell to move into:
|
||||
|
||||
// Check whether the line intersects the horizontal (top/bottom) edge of
|
||||
// the current navcell.
|
||||
// Horizontal edge is (i, j + (dj>0?1:0)) .. (i + 1, j + (dj>0?1:0))
|
||||
// Since we already know the line is moving from this navcell into a different
|
||||
// navcell, we simply need to test that the edge's endpoints are not both on the
|
||||
// same side of the line.
|
||||
|
||||
entity_pos_t xia = entity_pos_t::FromInt(i).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t xib = entity_pos_t::FromInt(i+1).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t zj = entity_pos_t::FromInt(j + (dj+1)/2).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
|
||||
CFixedVector2D perp = CFixedVector2D(x1 - x0, z1 - z0).Perpendicular();
|
||||
entity_pos_t dota = (CFixedVector2D(xia, zj) - CFixedVector2D(x0, z0)).Dot(perp);
|
||||
entity_pos_t dotb = (CFixedVector2D(xib, zj) - CFixedVector2D(x0, z0)).Dot(perp);
|
||||
|
||||
// If the horizontal edge is fully on one side of the line, so the line doesn't
|
||||
// intersect it, we should move across the vertical edge instead
|
||||
if ((dota < entity_pos_t::Zero() && dotb < entity_pos_t::Zero()) ||
|
||||
(dota > entity_pos_t::Zero() && dotb > entity_pos_t::Zero()))
|
||||
i += di;
|
||||
else
|
||||
j += dj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user