forked from 0ad/0ad
Add a hack in the pathfinder to pick more diagonal paths
This was SVN commit r7295.
This commit is contained in:
parent
1678055edd
commit
fa1fd65a3e
@ -460,23 +460,55 @@ static void ProcessNeighbour(u16 pi, u16 pj, u16 i, u16 j, u32 pg, PriorityQueue
|
||||
if (terrainGrid->get(i, j))
|
||||
return;
|
||||
|
||||
u32 cost = pg + g_CostPerTile;
|
||||
// TODO: should use terrain costs etc
|
||||
// Calculate the cost of moving from predecessor to here
|
||||
u32 dg = g_CostPerTile;
|
||||
|
||||
// Calculate heuristic cost to target
|
||||
// (This ought to be an underestimate for correctness)
|
||||
u32 h = (abs((int)i - (int)i1) + abs((int)j - (int)j1)) * g_CostPerTile;
|
||||
|
||||
if (1)
|
||||
{
|
||||
// XXX: Terrible hack:
|
||||
// For simplicity, we only consider horizontally/vertically adjacent neighbours, but
|
||||
// units can move along arbitrary lines. That results in ugly square paths, so we want
|
||||
// to prefer diagonal paths.
|
||||
// Instead of solving this nicely, I'll just special-case 45-degree and 30-degree lines
|
||||
// by checking the three predecessor tiles (which'll be in the closed set and therefore
|
||||
// likely to be reasonably stable) and reduce the cost, and use a Euclidean heuristic.
|
||||
// At least this makes paths look a bit nicer for now...
|
||||
|
||||
PathfindTile& p = tempGrid->get(pi, pj);
|
||||
if (p.pi != i && p.pj != j)
|
||||
dg = dg*(sqrt(2.0)/2.0);
|
||||
else
|
||||
{
|
||||
PathfindTile& pp = tempGrid->get(p.pi, p.pj);
|
||||
int di = abs(i - pp.pi);
|
||||
int dj = abs(j - pp.pj);
|
||||
if ((di == 1 && dj == 2) || (di == 2 && dj == 1))
|
||||
dg = dg*(sqrt(5.0)-sqrt(2.0));
|
||||
}
|
||||
|
||||
h = hypot(i-i1, j-j1)*g_CostPerTile;
|
||||
// XXX: shouldn't use floats here
|
||||
// Also, the heuristic should match the costs better
|
||||
}
|
||||
|
||||
u32 g = pg + dg;
|
||||
|
||||
PathfindTile& n = tempGrid->get(i, j);
|
||||
|
||||
// If we've already added this tile to the open list:
|
||||
if (n.status == PathfindTile::STATUS_OPEN)
|
||||
{
|
||||
// If this a better path, replace the old one with the new cost/parent
|
||||
if (cost < n.cost)
|
||||
if (g < n.cost)
|
||||
{
|
||||
n.cost = cost;
|
||||
n.cost = g;
|
||||
n.pi = pi;
|
||||
n.pj = pj;
|
||||
open.find(i, j)->rank = cost + h;
|
||||
open.find(i, j)->rank = g + h;
|
||||
open.fixheap(); // XXX: this is slow
|
||||
}
|
||||
return;
|
||||
@ -486,7 +518,7 @@ static void ProcessNeighbour(u16 pi, u16 pj, u16 i, u16 j, u32 pg, PriorityQueue
|
||||
if (n.status == PathfindTile::STATUS_CLOSED)
|
||||
{
|
||||
// If this is a better path (possible when we use inadmissible heuristics), reopen it
|
||||
if (cost < n.cost)
|
||||
if (g < n.cost)
|
||||
{
|
||||
closed.remove(i, j);
|
||||
// (don't return yet)
|
||||
@ -499,10 +531,10 @@ static void ProcessNeighbour(u16 pi, u16 pj, u16 i, u16 j, u32 pg, PriorityQueue
|
||||
|
||||
// Add it to the open list:
|
||||
n.status = PathfindTile::STATUS_OPEN;
|
||||
n.cost = cost;
|
||||
n.cost = g;
|
||||
n.pi = pi;
|
||||
n.pj = pj;
|
||||
QueueItem t = { i, j, cost + h };
|
||||
QueueItem t = { i, j, g + h };
|
||||
open.push(t);
|
||||
}
|
||||
|
||||
@ -524,6 +556,9 @@ void CCmpPathfinder::ComputePath(entity_pos_t x0, entity_pos_t z0, entity_pos_t
|
||||
QueueItem start = { i0, j0, 0 };
|
||||
open.push(start);
|
||||
tempGrid->get(i0, j0).status = PathfindTile::STATUS_OPEN;
|
||||
tempGrid->get(i0, j0).pi = i0;
|
||||
tempGrid->get(i0, j0).pj = j0;
|
||||
tempGrid->get(i0, j0).cost = 0;
|
||||
|
||||
u16 ip = i0, jp = j0; // the last tile on the path to the destination
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user