我的A *实施存在一些问题。它偶尔会决定在我的网格上做一些奇怪的事情,例如忽略移动成本并通过高成本区域移动,或者在回到正轨之前向错误的方向移动。
我已经正式花了太多时间,然后我想承认所以我伸手去寻找一双新鲜的眼睛。
private List<Vector2> PathFromTo(Vector2 startID, Vector2 targetID){
List<Vector2> path = new List<Vector2> ();
List<Node> closedList = new List<Node> ();
List<Node> openList = new List<Node> ();
Node startNode = nodeList.Find (tgt => tgt.nodeID == new Vector2 (startID.x, startID.y));
if (startNode == null)
return path;
Node targetNode = nodeList.Find (tgt => tgt.nodeID == new Vector2 (targetID.x, targetID.y));
if (targetNode == null)
return path;
openList.Add (startNode);
while (openList.Count > 0) {
Node current = openList [0];
for (int i = 1; i < openList.Count; i++)
if (openList [i].GetFCost () <= current.GetFCost () && openList [i].GetHCost () < current.GetHCost ())
current = openList [i];
openList.Remove (current);
closedList.Add (current);
if (current == targetNode) {
RetracePath (startNode, targetNode, ref path);
return path;
}
foreach(Vector2 neighbour in current.neighbors) {
Node neighbourNode = nodeList.Find (tgt => tgt.nodeID == new Vector2 (neighbour.x, neighbour.y));
CheckNeighbor(ref neighbourNode, ref current, ref targetNode, ref closedList, ref openList);
}
}
return path;
}
private void CheckNeighbor(ref Node neighborTile, ref Node currentTile, ref Node targetTile, ref List<Node> closedList, ref List<Node> openList){
if (neighborTile != null) {
if (!neighborTile.passable || closedList.Contains (neighborTile)) {
} else {
int newCostToNeighbor = (int)(currentTile.moveCost + CalculateDistance (currentTile.position, neighborTile.position));
if (newCostToNeighbor < neighborTile.GetGCost() || !openList.Contains (neighborTile)) {
neighborTile.SetGCost (newCostToNeighbor);
neighborTile.SetHCost (CalculateDistance (neighborTile.position, targetTile.position));
neighborTile.SetParent (currentTile);
if (!openList.Contains (neighborTile))
openList.Add (neighborTile);
}
}
}
}
public float CalculateDistance(Vector2 tileA_pos, Vector2 tileB_pos){
float dX = Mathf.Abs (tileB_pos.x - tileA_pos.x);
float dY = Mathf.Abs (tileB_pos.y - tileA_pos.y);
float shift1 = -(tileA_pos.x + tileA_pos.y);
float shift2 = -(tileB_pos.x + tileB_pos.y);
float dZ = Mathf.Abs (shift2 - shift1);
return Mathf.Max (dX, dY, dZ);
}
private void RetracePath(Node start, Node end, ref List<Vector2> pathInfo){
pathInfo = new List<Vector2> ();
Node current = end;
while (current != start) {
pathInfo.Add (current.nodeID);
current = current.GetParent ();
}
pathInfo.Reverse ();
}
答案 0 :(得分:1)
根据您在评论中显示的CalculateDistance
方法,我编写了以下测试程序:(假设您的Mathf
与System.Math
类似)
for (int y = -4; y < 5; y++)
{
for (int x = -4; x < 5; x++)
{
var dst = CalculateDistance(new Vector2(x, y), new Vector2());
Console.Write($"{((int)dst):D1} ");
}
Console.WriteLine();
}
测试程序测试(-4,-4)和(4,4)之间的所有坐标并计算它们到(0,0)的距离输出:
8 7 6 5 4 4 4 4 4
7 6 5 4 3 3 3 3 4
6 5 4 3 2 2 2 3 4
5 4 3 2 1 1 2 3 4
4 3 2 1 0 1 2 3 4
4 3 2 1 1 2 3 4 5
4 3 2 2 2 3 4 5 6
4 3 3 3 3 4 5 6 7
4 4 4 4 4 5 6 7 8
正如你可以看到输出是完全古怪的,你会期望右下角与右上角的距离(0,0)一样远,但事实并非如此。也许您需要重写CalculateDistance
方法。
你似乎计算了dX,dY和dZ,这是不可能的,因为你只有2个坐标(Vector2
)。
编辑:如果没有记录'权重',你可以简单地使用毕达哥拉斯来计算两点之间的距离:
var dist = Math.Sqrt(Math.Pow(point1.x - point2.x, 2) + Math.Pow(point1.y - point2.y, 2));
答案 1 :(得分:0)
你不能说明你是否允许对角移动,但是这两个CalculateDistance例程中的一个应该足够了:
public static readonly int D = 1;
public static readonly int D2 = 1;
public static float CalculateDistance(Vector2 tileA_pos, Vector2 tileB_pos)
{
float dX = Math.Abs(tileB_pos.x - tileA_pos.x);
float dY = Math.Abs(tileB_pos.y - tileA_pos.y);
return D * (dX + dY);
}
public static float CalculateDistanceDiagonalsAllowed(Vector2 tileA_pos, Vector2 tileB_pos)
{
float dX = Math.Abs(tileB_pos.x - tileA_pos.x);
float dY = Math.Abs(tileB_pos.y - tileA_pos.y);
return D * (dX + dY) + (D2 - 2 * D) * (dX < dY ? dX : dY);
}
其中D是垂直/水平移动的成本,D2是对角线移动的成本 - 您可能希望根据需要将其设置为1或Sqrt(2)。我假设currentTile.moveCost用于定义高/低成本瓦片
答案 2 :(得分:0)
经过太多时间(整夜睡眠),我能够弄清楚。问题与CheckNeighbor功能有关。新方法如下所示:
private void CheckNeighbor(ref Node neighborTile, ref Node currentTile, ref Node targetTile, ref List<Node> closedList, ref List<Node> openList, bool ignoreMoveCost = false){
if (neighborTile != null) {
if (!neighborTile.passable || closedList.Contains (neighborTile)) {
} else {
int newCostToNeighbor = (int)((ignoreMoveCost ? 1 : neighborTile.moveCost) + currentTile.GetGCost() + CalculateDistance (currentTile.position, neighborTile.position));
if (!openList.Contains (neighborTile)) {
openList.Add (neighborTile);
} else if (newCostToNeighbor >= neighborTile.GetGCost ()) {
return;
}
neighborTile.SetParent (currentTile);
neighborTile.SetGCost (newCostToNeighbor);
neighborTile.SetHCost (CalculateDistance (currentTile.position, neighborTile.position));
}
}
}