我正在使用XNA中的Isometric游戏,并使用A *版本进行寻路。
它运作良好,但我在找对角线移动时找到最佳路线有问题。而不是沿对角线(最短的路线)返回的路径直接向上然后穿过。
我一直在网上阅读,但无法弄清楚如何改变它。我想我需要改变预测距离,而不是* 10,对于直接在上方或下方的瓷砖,这将是* 14,但这似乎不起作用......
public List<Point> Pathfind(Point start, Point end)
{
// nodes that have already been analyzed and have a path from the start to them
var closedSet = new List<Point>();
// nodes that have been identified as a neighbor of an analyzed node, but have
// yet to be fully analyzed
var openSet = new List<Point> { start };
// a dictionary identifying the optimal origin point to each node. this is used
// to back-track from the end to find the optimal path
var cameFrom = new Dictionary<Point, Point>();
// a dictionary indicating how far each analyzed node is from the start
var currentDistance = new Dictionary<Point, int>();
// a dictionary indicating how far it is expected to reach the end, if the path
// travels through the specified node.
var predictedDistance = new Dictionary<Point, float>();
// initialize the start node as having a distance of 0, and an estmated distance
// of y-distance + x-distance, which is the optimal path in a square grid that
// doesn't allow for diagonal movement
currentDistance.Add(start, 0);
predictedDistance.Add(
start,
0 + +Math.Abs(start.X - end.X) + Math.Abs(start.Y - end.Y)
);
// if there are any unanalyzed nodes, process them
while (openSet.Count > 0)
{
// get the node with the lowest estimated cost to finish
var current = (from p in openSet orderby predictedDistance[p] ascending select p).First();
// if it is the finish, return the path
if (current.X == end.X && current.Y == end.Y)
{
// generate the found path
return ReconstructPath(cameFrom, end);
}
// move current node from open to closed
openSet.Remove(current);
closedSet.Add(current);
// process each valid node around the current node
foreach (var neighbor in GetNeighborNodes(current))
{
var tempCurrentDistance = currentDistance[current] + 1;
// if we already know a faster way to this neighbor, use that route and
// ignore this one
if (closedSet.Contains(neighbor) && tempCurrentDistance >= currentDistance[neighbor])
{
continue;
}
// NOT PASSABLE
if (Globals.mapArray[neighbor.X,neighbor.Y].Passable == false)
{
continue;
}
// if we don't know a route to this neighbor, or if this is faster,
// store this route
if (!closedSet.Contains(neighbor)|| tempCurrentDistance < currentDistance[neighbor])
{
if (cameFrom.Keys.Contains(neighbor))
{
cameFrom[neighbor] = current;
}
else
{
cameFrom.Add(neighbor, current);
}
currentDistance[neighbor] = tempCurrentDistance + 10;
predictedDistance[neighbor] = currentDistance[neighbor] + Math.Abs(neighbor.X - end.X) + Math.Abs(neighbor.Y - end.Y);
predictedDistance[neighbor] = predictedDistance[neighbor] * 10;
// if this is a new node, add it to processing
if (!openSet.Contains(neighbor))
{
openSet.Add(neighbor);
}
}
}
}
// unable to figure out a path, abort.
List<Point> noPath = new List<Point>();
Point n = new Point();
n.X = -1; n.Y = -1;
noPath.Add(n);
return noPath;
}
private IEnumerable<Point> GetNeighborNodes(Point node)
{
var nodes = new List<Point>();
if (node.X > 0 && node.Y > 0 && node.X < Globals.xSize - 1 && node.Y < Globals.ySize - 1)
{
// up
nodes.Add(new Point(node.X, node.Y - 2));
// right
nodes.Add(new Point(node.X + 1, node.Y));
// down
nodes.Add(new Point(node.X, node.Y + 2));
// left
nodes.Add(new Point(node.X - 1, node.Y));
// DIAGONAL
if (node.Y % 2 == 0)
{
// UP LEFT
nodes.Add(new Point(node.X, node.Y - 1));
// UP RIGHT
nodes.Add(new Point(node.X - 1, node.Y - 1));
// DOWN LEFT
nodes.Add(new Point(node.X-1, node.Y + 1));
// DOWN RIGHT
nodes.Add(new Point(node.X, node.Y + 1));
}
else
{
// UP LEFT
nodes.Add(new Point(node.X+1, node.Y - 1));
// UP RIGHT
nodes.Add(new Point(node.X, node.Y - 1));
// DOWN LEFT
nodes.Add(new Point(node.X, node.Y + 1));
// DOWN RIGHT
nodes.Add(new Point(node.X+1, node.Y + 1));
}
}
return nodes;
}