如何在网格上使用A *制作看起来自然的路径?


13

我一直在阅读:http : //theory.stanford.edu/~amitp/GameProgramming/Heuristics.html

但是有些事情我不理解,例如,文章说使用这样的东西进行对角线运动的寻路:

function heuristic(node) =
    dx = abs(node.x - goal.x)
    dy = abs(node.y - goal.y)
    return D * max(dx, dy)

我不知道如何像本文中那样设置D来获得自然的外观路径,就像上面所说的那样,我将D设置为相邻正方形之间的最低成本,而且我不知道它们对启发式技术的意义是什么。是4 * D,那似乎并没有改变任何事情。

这是我的启发式功能和移动功能:

def heuristic(self, node, goal):
    D = 5
    dx = abs(node.x - goal.x)
    dy = abs(node.y - goal.y)
    return D * max(dx, dy)

def move_cost(self, current, node):
   cross = abs(current.x - node.x) == 1 and abs(current.y - node.y) == 1
   return 7 if cross else 5

结果:

在此处输入图片说明

我们希望实现的顺利航行路线:

在此处输入图片说明

我的其余代码:http : //pastebin.com/TL2cEkeX


更新资料

这是到目前为止我发现的最好的解决方案:

def heuristic(node, start, goal):
    dx1 = node.x - goal.x
    dy1 = node.y - goal.y
    dx2 = start.x - goal.x
    dy2 = start.y - goal.y
    cross = abs(dx1*dy2 - dx2*dy1)

    dx3 = abs(dx1)
    dy3 = abs(dy1)

    return 5 + (cross*0.01) * (dx3+dy3) + (sqrt(2)-2) * min(dx3, dy3)

def move_cost(current, node):
    cross = abs(current.x - node.x) == 1 and abs(current.y - node.y) == 1
    return 7 if cross else 5

它会从第二张图片中产生所需的路径,但不能很好地处理障碍物(容易在墙壁上爬行),有时甚至无法在更长的距离上产生最佳路径。

我可以应用哪些调整和优化来改进它?


2
如果您使用笛卡尔距离作为启发式方法怎么办?
吉米

2
这只是一个想法,增加了代理沿着相同方向移动的每一步从一个图块移动到另一个图块的成本。
Ali1S232

@Jimmy我尝试了sqrt(pow(goal.x-node.x,2)+ pow(goal.y-node.y,2)),对于我的小示例路径,它实际上返回的图像与问题中的图片完全相同。
匿名实体

Answers:


10

A *为您提供图形中最短的路径。当使用网格作为图形时,通常会有多个最短路径。在第一个图中,这最短的路径之一。它首先放置所有轴向运动,然后放置所有对角线运动。但这与将所有对角线放在第一位或混合轴向和对角线运动时的长度路径相同。这些都相当短,一个A *选择哪个取决于代码的编写方式和图形表示方式。

我想您想要的是:

  1. 您需要在网格上移动,但是您想要混合轴向和对角线步长,以便看起来更好。一种方法是选择其他同样短的路径之一。继续阅读启发式页面以查找“打破常规”。另一种方法是,当您评估邻居时,随机选择首先评估哪个邻居,这样它就不会总是先选择一个。我推荐使用欧氏/笛卡尔距离,如果你想在网格上移动; 这是不匹配的结果,导致A *运行速度变慢。
  2. 您不需要在网格上移动,而是想直线移动。一种方法是使用“拉线”理顺路径。您正在寻找路径转弯的地方,并在这些点之间绘制直线。另一种方法是将其应用于基础图本身。在地图上的关键点上寻路,而不是在网格上寻路,然后沿着这些关键点之间的直线移动。您可以在此处查看示例。另一个方法是Theta *算法

好答案。我用一些新信息更新了我的问题,希望您可以指定一些答案。
匿名实体

我认为应该有一些障碍。启发式页面上有一个标题为“障碍较少的图表”。抢七的方法对解决障碍没有太大帮助。您可能需要其他方法之一(例如Theta *)。
amitp

2

A *算法允许您将不同的成本分配给路径边缘。您还可以根据情况分配成本。这是您将A *路径整形为所需外观的主要工具。

如果您不希望使用长对角线,可以对它们进行惩罚。每次沿同一方向行驶时,都会增加一点成本。执行此操作时,算法将自动尝试在整个路径上尽可能均匀地分布对角线步。只要确保这笔额外的费用永远不会超过获得一条额外边缘的费用,否则该算法将开始进行完全不必要的弯路,以避免直线。

一个好的公式可能是:

cost = normal_cost * (1.1 - 0.1 / num_of_steps_in_the_same_direction

请注意,这要求将路径成本作为浮点值而不是整数进行跟踪。


1

适应A *

正如Philipp所说,当方向长期不变时,您应该增加成本。但是,菲利普(Philipp)的功能可能会很快导致对额外成本的汇总,该成本高于遍历额外图块的成本。但是他的关键思想是正确的!

调整A *来计算“所有”最佳路径(具有最短长度),然后通过另一种启发式选择其中一个似乎很容易。但有一个问题。如果您的路线很长,可能会有很多解决方案都具有最佳长度。这也导致A *算法花费更长的时间来计算所有其他解决方案。这是因为网格。您不能走80度而不是90度,这会导致多个次优解决方案而不是一个最佳解决方案。为了发挥想象力,请想象没有障碍的地图。x距离为2,y距离为3。这意味着,所有最短路径都有2个对角线移动和1个直线移动。此简单路径有3种有效组合:SDD,DSD,DDS(其中D =对角线,S =直线)。当您具有例如路径时,真正的“乐趣”已经开始 3条直线和2条对角线移动:SSSDD,SSDSD,SSDDS,SDSSD,SDSDS,SDDSS,DSSSD,DSSDS,DSDSS,DDSSS(最短路径的10种变化,如果我没错过的话)。我想你应该有个主意...

因此,我们应该通过调整成本函数来解决此问题,使更少的解决方案(甚至只有一个解决方案)是“最佳”的。

调整成本函数

像Philipp在他的示例公式中建议的那样进行改编将为您带来更好的结果,但仍然存在一些问题。它不会沿路径均匀分布较短/较长的“部分”,这意味着:方向更改将更多地出现在路径的开头,反之亦然。

另外,当被人观察时,使演员无休止地“转向”的路径似乎不是最佳的。由于需要时间(显示转弯动画),因此它必须较慢。

但是,可以使用“次级成本”或次级排序条件来代替使用浮点数作为成本。如果主要成本相同,则使用次要成本来估计首选哪种解决方案。这不会偶然导致主要成本(网格度量中的路由长度)增加。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.