在C#中修复A *实现

时间:2018-05-05 08:37:45

标签: c# unity3d unityscript a-star

所以我在Unity C#中实现了一个A *算法来做一些测试,以便构建一个基于2D的游戏。我知道有几个组件可以帮助你解决这个问题,但我想尝试自己只是为了挑战。

我基本上已经阅读了A *应该如何表现并将行为转换为代码。它几乎可以工作。但是有一些观点,相邻的瓷砖具有完全相同的分数(曼哈顿距离+距离原点的距离),并且您最终得到的路径通向目的地但不是最短的。正如你在图像中看到的那样,那两个相邻的瓷砖具有相同的分数,但我在那一点上随机选取...(在下图中,起点是猫,红叉是目的点。绿色半透明文件是计算出的路径)

enter image description here

我在想,因为没有太多的瓷砖,我可以从4个初始相邻瓷砖中计算出4个不同的路径,将有效的路径存储在一个数组中,然后基本上只使用最短的,但也许会是太多的开销,还有另一种解决方案吗?

使用基本计算计算距离I

private int CalculateManhattanDistance(int x1, int x2, int y1, int y2)
{
        return Mathf.Abs(x1 - x2) + Mathf.Abs(y1 - y2);
}

2 个答案:

答案 0 :(得分:3)

也许这有助于您了解@ZdeněkJelínek和@Peter Wishart所指出的内容。 openSet(也称为frontier)通常是PriorityQueue。队列的节点根据其优先级进行排序。节点的优先级计算为到目前为止的成本(案例中的步数)和启发式距离(在您的情况下为曼哈顿)的总和。因此,一旦A *到达优先级为11的节点,它将停止探索该路径并继续其他路径(蓝色圆圈)

答案 1 :(得分:2)

我建议您针对代码检查 A * e.g. on Wikipedia的伪代码。

基于那个伪代码你会像这样实现算法数据,我怀疑你已经简化了其中的一些:

        var closedSet = new HashSet<GraphNode>();
        var openSet = new List<GraphNode>{startNode};
        var cameFrom = new Dictionary<GraphNode, GraphNode>();
        var gScore = new Dictionary<GraphNode, double>();
        var fScore = new Dictionary<GraphNode, double>();

当算法对启发式算法做出错误的首选时,就像在这个测试用例中一样,它最初会评估错误方向的移动。 但这应该不是问题:

  • 选择最低fScore
  • 的开放节点
  • 评估所有可到达的邻居(例如,在示例的第一次迭代中将节点包含到起始节点的 left
  • 使用实际距离更新gScore(通过cameFrom)
  • 使用实际距离加估算(例如曼哈顿)到目标的距离
  • 更新fScore
  • 将评估的节点从openSet移至closedSet

这意味着沿着“错误”路径的节点将计算增加的​​实际+预期距离,达到算法开始选择其他open节点的程度,例如第一次迭代中的“右”节点。