Use CellLayer for pathfinding.
This commit is contained in:
@@ -12,6 +12,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
@@ -136,9 +137,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
|
|
||||||
var dbg = world.WorldActor.TraitOrDefault<PathfinderDebugOverlay>();
|
var dbg = world.WorldActor.TraitOrDefault<PathfinderDebugOverlay>();
|
||||||
if (dbg != null)
|
if (dbg != null)
|
||||||
{
|
dbg.AddLayer(search.Considered.Select(p => new Pair<CPos, int>(p, search.CellInfo[p].MinCost)), search.MaxCost, search.Owner);
|
||||||
dbg.AddLayer(search.Considered.Select(p => new Pair<CPos, int>(p, search.CellInfo[p.X, p.Y].MinCost)), search.MaxCost, search.Owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path != null)
|
if (path != null)
|
||||||
return path;
|
return path;
|
||||||
@@ -149,15 +148,15 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<CPos> MakePath(CellInfo[,] cellInfo, CPos destination)
|
static List<CPos> MakePath(CellLayer<CellInfo> cellInfo, CPos destination)
|
||||||
{
|
{
|
||||||
var ret = new List<CPos>();
|
var ret = new List<CPos>();
|
||||||
var pathNode = destination;
|
var pathNode = destination;
|
||||||
|
|
||||||
while (cellInfo[pathNode.X, pathNode.Y].Path != pathNode)
|
while (cellInfo[pathNode].Path != pathNode)
|
||||||
{
|
{
|
||||||
ret.Add(pathNode);
|
ret.Add(pathNode);
|
||||||
pathNode = cellInfo[pathNode.X, pathNode.Y].Path;
|
pathNode = cellInfo[pathNode].Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.Add(pathNode);
|
ret.Add(pathNode);
|
||||||
@@ -165,9 +164,8 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CPos> FindBidiPath( /* searches from both ends toward each other */
|
// Searches from both ends toward each other
|
||||||
PathSearch fromSrc,
|
public List<CPos> FindBidiPath(PathSearch fromSrc, PathSearch fromDest)
|
||||||
PathSearch fromDest)
|
|
||||||
{
|
{
|
||||||
using (new PerfSample("Pathfinder"))
|
using (new PerfSample("Pathfinder"))
|
||||||
{
|
{
|
||||||
@@ -181,8 +179,8 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
/* make some progress on the first search */
|
/* make some progress on the first search */
|
||||||
var p = fromSrc.Expand(world);
|
var p = fromSrc.Expand(world);
|
||||||
|
|
||||||
if (fromDest.CellInfo[p.X, p.Y].Seen &&
|
if (fromDest.CellInfo[p].Seen &&
|
||||||
fromDest.CellInfo[p.X, p.Y].MinCost < float.PositiveInfinity)
|
fromDest.CellInfo[p].MinCost < float.PositiveInfinity)
|
||||||
{
|
{
|
||||||
path = MakeBidiPath(fromSrc, fromDest, p);
|
path = MakeBidiPath(fromSrc, fromDest, p);
|
||||||
break;
|
break;
|
||||||
@@ -191,8 +189,8 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
/* make some progress on the second search */
|
/* make some progress on the second search */
|
||||||
var q = fromDest.Expand(world);
|
var q = fromDest.Expand(world);
|
||||||
|
|
||||||
if (fromSrc.CellInfo[q.X, q.Y].Seen &&
|
if (fromSrc.CellInfo[q].Seen &&
|
||||||
fromSrc.CellInfo[q.X, q.Y].MinCost < float.PositiveInfinity)
|
fromSrc.CellInfo[q].MinCost < float.PositiveInfinity)
|
||||||
{
|
{
|
||||||
path = MakeBidiPath(fromSrc, fromDest, q);
|
path = MakeBidiPath(fromSrc, fromDest, q);
|
||||||
break;
|
break;
|
||||||
@@ -202,8 +200,8 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
var dbg = world.WorldActor.TraitOrDefault<PathfinderDebugOverlay>();
|
var dbg = world.WorldActor.TraitOrDefault<PathfinderDebugOverlay>();
|
||||||
if (dbg != null)
|
if (dbg != null)
|
||||||
{
|
{
|
||||||
dbg.AddLayer(fromSrc.Considered.Select(p => new Pair<CPos, int>(p, fromSrc.CellInfo[p.X, p.Y].MinCost)), fromSrc.MaxCost, fromSrc.Owner);
|
dbg.AddLayer(fromSrc.Considered.Select(p => new Pair<CPos, int>(p, fromSrc.CellInfo[p].MinCost)), fromSrc.MaxCost, fromSrc.Owner);
|
||||||
dbg.AddLayer(fromDest.Considered.Select(p => new Pair<CPos, int>(p, fromDest.CellInfo[p.X, p.Y].MinCost)), fromDest.MaxCost, fromDest.Owner);
|
dbg.AddLayer(fromDest.Considered.Select(p => new Pair<CPos, int>(p, fromDest.CellInfo[p].MinCost)), fromDest.MaxCost, fromDest.Owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path != null)
|
if (path != null)
|
||||||
@@ -222,19 +220,19 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
var ret = new List<CPos>();
|
var ret = new List<CPos>();
|
||||||
|
|
||||||
var q = p;
|
var q = p;
|
||||||
while (ca[q.X, q.Y].Path != q)
|
while (ca[q].Path != q)
|
||||||
{
|
{
|
||||||
ret.Add(q);
|
ret.Add(q);
|
||||||
q = ca[q.X, q.Y].Path;
|
q = ca[q].Path;
|
||||||
}
|
}
|
||||||
ret.Add(q);
|
ret.Add(q);
|
||||||
|
|
||||||
ret.Reverse();
|
ret.Reverse();
|
||||||
|
|
||||||
q = p;
|
q = p;
|
||||||
while (cb[q.X, q.Y].Path != q)
|
while (cb[q].Path != q)
|
||||||
{
|
{
|
||||||
q = cb[q.X, q.Y].Path;
|
q = cb[q].Path;
|
||||||
ret.Add(q);
|
ret.Add(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,14 +10,16 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA.Move
|
namespace OpenRA.Mods.RA.Move
|
||||||
{
|
{
|
||||||
public sealed class PathSearch : IDisposable
|
public sealed class PathSearch : IDisposable
|
||||||
{
|
{
|
||||||
public CellInfo[,] CellInfo;
|
public CellLayer<CellInfo> CellInfo;
|
||||||
public PriorityQueue<PathDistance> Queue;
|
public PriorityQueue<PathDistance> Queue;
|
||||||
public Func<CPos, int> Heuristic;
|
public Func<CPos, int> Heuristic;
|
||||||
public bool CheckForBlocked;
|
public bool CheckForBlocked;
|
||||||
@@ -141,7 +143,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
public CPos Expand(World world)
|
public CPos Expand(World world)
|
||||||
{
|
{
|
||||||
var p = Queue.Pop();
|
var p = Queue.Pop();
|
||||||
while (CellInfo[p.Location.X, p.Location.Y].Seen)
|
while (CellInfo[p.Location].Seen)
|
||||||
{
|
{
|
||||||
if (Queue.Empty)
|
if (Queue.Empty)
|
||||||
return p.Location;
|
return p.Location;
|
||||||
@@ -149,7 +151,9 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
p = Queue.Pop();
|
p = Queue.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo[p.Location.X, p.Location.Y].Seen = true;
|
var pCell = CellInfo[p.Location];
|
||||||
|
pCell.Seen = true;
|
||||||
|
CellInfo[p.Location] = pCell;
|
||||||
|
|
||||||
var thisCost = mobileInfo.MovementCostForCell(world, p.Location);
|
var thisCost = mobileInfo.MovementCostForCell(world, p.Location);
|
||||||
|
|
||||||
@@ -177,7 +181,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
if (!world.Map.IsInMap(newHere))
|
if (!world.Map.IsInMap(newHere))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (CellInfo[newHere.X, newHere.Y].Seen)
|
if (CellInfo[newHere].Seen)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Now we may seriously consider this direction using heuristics:
|
// Now we may seriously consider this direction using heuristics:
|
||||||
@@ -224,14 +228,16 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
cellCost += laneBias;
|
cellCost += laneBias;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newCost = CellInfo[p.Location.X, p.Location.Y].MinCost + cellCost;
|
var newCost = CellInfo[p.Location].MinCost + cellCost;
|
||||||
|
|
||||||
// Cost is even higher; next direction:
|
// Cost is even higher; next direction:
|
||||||
if (newCost > CellInfo[newHere.X, newHere.Y].MinCost)
|
if (newCost > CellInfo[newHere].MinCost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CellInfo[newHere.X, newHere.Y].Path = p.Location;
|
var hereCell = CellInfo[newHere];
|
||||||
CellInfo[newHere.X, newHere.Y].MinCost = newCost;
|
hereCell.Path = p.Location;
|
||||||
|
hereCell.MinCost = newCost;
|
||||||
|
CellInfo[newHere] = hereCell;
|
||||||
|
|
||||||
nextDirections[i].Second = newCost + est;
|
nextDirections[i].Second = newCost + est;
|
||||||
Queue.Add(new PathDistance(newCost + est, newHere));
|
Queue.Add(new PathDistance(newCost + est, newHere));
|
||||||
@@ -252,27 +258,28 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
if (!self.World.Map.IsInMap(location))
|
if (!self.World.Map.IsInMap(location))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CellInfo[location.X, location.Y] = new CellInfo(0, location, false);
|
CellInfo[location] = new CellInfo(0, location, false);
|
||||||
Queue.Add(new PathDistance(Heuristic(location), location));
|
Queue.Add(new PathDistance(Heuristic(location), location));
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly Queue<CellInfo[,]> CellInfoPool = new Queue<CellInfo[,]>();
|
static readonly Queue<CellLayer<CellInfo>> CellInfoPool = new Queue<CellLayer<CellInfo>>();
|
||||||
|
|
||||||
static CellInfo[,] GetFromPool()
|
static CellLayer<CellInfo> GetFromPool()
|
||||||
{
|
{
|
||||||
lock (CellInfoPool)
|
lock (CellInfoPool)
|
||||||
return CellInfoPool.Dequeue();
|
return CellInfoPool.Dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PutBackIntoPool(CellInfo[,] ci)
|
static void PutBackIntoPool(CellLayer<CellInfo> ci)
|
||||||
{
|
{
|
||||||
lock (CellInfoPool)
|
lock (CellInfoPool)
|
||||||
CellInfoPool.Enqueue(ci);
|
CellInfoPool.Enqueue(ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo[,] InitCellInfo()
|
CellLayer<CellInfo> InitCellInfo()
|
||||||
{
|
{
|
||||||
CellInfo[,] result = null;
|
CellLayer<CellInfo> result = null;
|
||||||
|
var mapSize = new Size(self.World.Map.MapSize.X, self.World.Map.MapSize.Y);
|
||||||
|
|
||||||
// HACK: Uses a static cache so that double-ended searches (which have two PathSearch instances)
|
// HACK: Uses a static cache so that double-ended searches (which have two PathSearch instances)
|
||||||
// can implicitly share data. The PathFinder should allocate the CellInfo array and pass it
|
// can implicitly share data. The PathFinder should allocate the CellInfo array and pass it
|
||||||
@@ -280,8 +287,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
while (CellInfoPool.Count > 0)
|
while (CellInfoPool.Count > 0)
|
||||||
{
|
{
|
||||||
var cellInfo = GetFromPool();
|
var cellInfo = GetFromPool();
|
||||||
if (cellInfo.GetUpperBound(0) != self.World.Map.MapSize.X - 1 ||
|
if (cellInfo.Size != mapSize)
|
||||||
cellInfo.GetUpperBound(1) != self.World.Map.MapSize.Y - 1)
|
|
||||||
{
|
{
|
||||||
Log.Write("debug", "Discarding old pooled CellInfo of wrong size.");
|
Log.Write("debug", "Discarding old pooled CellInfo of wrong size.");
|
||||||
continue;
|
continue;
|
||||||
@@ -292,11 +298,10 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
result = new CellInfo[self.World.Map.MapSize.X, self.World.Map.MapSize.Y];
|
result = new CellLayer<CellInfo>(self.World.Map);
|
||||||
|
|
||||||
for (var x = 0; x < self.World.Map.MapSize.X; x++)
|
foreach (var cell in self.World.Map.Cells)
|
||||||
for (var y = 0; y < self.World.Map.MapSize.Y; y++)
|
result[cell] = new CellInfo(int.MaxValue, cell, false);
|
||||||
result[x, y] = new CellInfo(int.MaxValue, new CPos(x, y), false);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user