【发布时间】:2017-05-09 08:38:43
【问题描述】:
我的 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 ();
}
【问题讨论】:
-
你已经尝试了什么?你能重现你的问题吗?如果是这样,您是否尝试过调试代码以至少尝试查明哪里出了问题?
-
我尝试过弄乱路径成本和起始位置,但我使用的电路板使用了一些随机生成,因此可能有点难以确定确切的模式。最坏的地方是瓷砖可以通过但移动成本很高的地方。它不是绕过瓷砖,而是穿过它们。瓦片成本是正确的,它只是生成了不正确的路径,因此,我认为实现是不正确的。
-
您可以记录/存储随机函数的种子,以便更轻松地重现问题。您可以使用种子初始化随机函数,以使其始终产生相同的结果。无论如何,关于你的代码:我的感觉是你的问题与
CheckNeighbor中的int newCostToNeighbor = ...行有关,你确定你需要currentTile.moveCost而不是neighborTile.moveCost? -
您提到“高成本瓷砖”,这在您的代码示例中并不明显。 (如何)这是在
CalculateDistance中处理的吗? -
@NickB。您应该编辑您的问题以添加您的 CalculateDistance 方法。代码太多,无法很好地放在评论中。之后也请删除该评论。哦,当您编辑您的问题时,请同时删除其中的 [oop] 标签,因为您的问题与面向对象编程无关(例如,您没有任何继承或抽象问题)。
标签: c# unity3d path-finding a-star