使用(部分)均匀网格表示法来减少3D A*路径搜索中的节点数

4
我正在计算一张网格内的路径规划,我已经在其周围建立了一个均匀的网格。我标记了靠近我认为是“可站立”表面的节点(3D网格中的单元格)作为可访问的,并将它们用于我的路径规划。为了获得更多细节(例如能够通过小楼梯寻路),我的网格中的可访问单元格数量已经相当大,在较大的建筑物中达到数千个。(每个网格单元格大小为0.5x0.5x0.5米,网格是具有现实世界尺寸的房间)。即使我只在路径规划中使用了实际单元格的一小部分,但巨大的数量也会拖慢算法速度。除此之外,它可以正常工作并找到正确的路径,使用加权曼哈顿距离启发式方法。

enter image description here

想象一下我的网格看起来像这样,网格在其中(可以是更多或更少的立方体,但始终是立方体),然而路径规划不会在所有小立方体上计算,只有少数标记为可访问(通常在网格底部,但这取决于网格有多少层)。

我希望减少路径规划的搜索空间... 我已经研究了类似 HPA* 的聚类和其他聚类算法,例如马尔科夫,但它们似乎最适用于节点图而不是网格。一个显而易见的解决方案就是增加构建网格的小立方体的大小,但那样我将失去路径规划中很多细节,并且它将不够稳健。如何对这些小立方体进行聚类?当我进行路径规划时,典型的搜索空间就是这样的(蓝色是可访问的,绿色是路径):

enter image description here

如您所见,要搜索的立方体数量很多,因为它们之间的距离非常小!现在不用担心网格路径查找不够优化。

有人有什么想法可以减少我需要搜索的网格中的立方体数量吗?当我缩小空间后,如何访问邻居呢? :) 目前它只查看最近的邻居并扩展搜索空间。


阅读这篇文章时,我首先想到的是八叉树:https://de.wikipedia.org/wiki/Octree - nyro_0
是的,我确实已经实现了一个八叉树,但目前没有使用。然而,我不确定如何在体积之间移动(查找体积之间对角线相邻的立方体)。我也不确定这实际上会如何帮助我。是的,它会构建类似于体积的聚类,但没有关于其中立方体的任何知识,但不确定如何更快地在它们上面进行路径规划 :s - soncis
网格只是有向图的一种特殊形式。由于网格的本质,任何你需要的图形都是隐含的。 - yes
真的吗?那么它具有一些非常好的属性。所以我猜你这个神秘的意思是,在网格上实现一些集群算法和在图上一样容易(或困难)? - soncis
我不知道我从哪里得到了那个方向。当然,它是一个无向图。如果你在上面使用a*算法,你已经将其作为一个图形使用了。网格单元是一个节点,边缘是允许的移动。 - yes
1个回答

10

我想到了几个可能性。

更高级的路径规划

首先,你的A*搜索可能在搜索整个问题空间。例如,你住在德克萨斯州奥斯汀市,想要进入加拿大艾伯塔省的某个建筑物。一个简单的A*算法会在最终搜索加拿大之前搜索许多墨西哥和美国。

考虑创建第二层A*来解决这个问题。你首先需要找出要穿越哪些州才能到达加拿大,然后是要到达艾伯塔省,卡尔加里市,再到卡尔加里动物园等等。从某种意义上说,你从概述开始,然后填充更详细的路径。

如果你有像《上古卷轴5》那样巨大的关卡,你可能需要在城镇(多个建筑物)、地区(多个城镇)甚至国家(多个地区)之间添加路径规划层。如果你正在制作GPS系统,你甚至可能需要大陆级别的路径规划。如果我们成为星际文明,我们的太空飞船可能会包含行星、星区甚至银河系的路径规划层。

通过使用图层,您可以显著缩小搜索区域,特别是如果不同的区域不使用相同的坐标系统!(如果其中一个区域需要纬度经度,另一个需要三维笛卡尔,下一个需要通过时间维度进行路径查找,则很难估计一个A *寻路器的距离。)

更有效率的算法

在三维中查找变得更加重要,因为在搜索时需要扩展更多节点。Dijkstra搜索扩展x ^ 2个节点,而x是起点和终点之间的距离,则需要搜索x ^ 3个节点。在四维游戏中,需要更高效的路径查找。

基于网格的路径查找的好处之一是可以利用地形属性,如路径对称性。如果两条路径由相同的移动按不同顺序组成,则不需要同时查找它们。这就是一个非常高效的算法Jump Point Search发挥作用的地方。

以下是A *(左)和JPS(右)的并排比较。展开/搜索的节点以红色显示,墙壁以黑色显示:

请注意,它们都找到了相同的路径,但JPS搜索的内容少于A*的十分之一。

目前为止,我还没有看到官方的三维实现,但我已经帮助另一个用户将算法推广到多个维度

简化网格(图)

另一种在搜索过程中消除节点的方法是在搜索之前移除它们。例如,在你可以信任一个更加愚蠢的AI找到路线的开阔区域中,你真的需要节点吗?如果你正在构建不会改变的关卡,请创建一个脚本,将其解析成仅包含重要节点的最简单网格。

这实际上被称为“离线路径规划”;基本上就是在需要找到路径之前寻找计算路径的方法。如果你的关卡将保持不变,每次更新关卡时运行脚本几分钟就可以轻松削减90%的路径查找时间。毕竟,在紧急情况出现之前,你已经完成了大部分工作。这就像在新城市里找路和在自己成长的城市里找路一样;知道地标意味着你不需要真正的地图。

类似于跳点搜索使用的“对称性破坏”的方法是由算法的创建者Daniel Harabor引入的。他在其讲座中提到了这些方法,可以预处理级别以仅存储路径查找网格中的跳点。
巧妙的启发式方法
许多学术论文指出A*的成本函数为f(x) = g(x) + h(x),这并不意味着你不能使用其他函数、乘以成本函数的权重,甚至实现领土或最近死亡的热图作为函数。这些可能会产生次优路径,但它们极大地提高了搜索的智能。当你的对手在最短路径上有一个阻塞点,并且一直轻松地消灭通过它的任何人时,谁还关心最短路径呢?更好的办法是确保AI可以安全地达到目标,而不是让它变得愚蠢。
例如,您可能希望防止算法让敌人进入秘密区域,以避免他们向玩家透露这些区域,使AI似乎对它们不知情。要实现这一点,您只需要为那些“禁止”区域内的任何点设置统一的成本函数。在这样的游戏中,敌人会在路径变得过于昂贵之后放弃追捕玩家。另一个很酷的选项是“嗅探”玩家最近去过的区域(通过暂时增加未被访问位置的成本,因为许多算法不喜欢负成本)。
如果您知道哪些地方不需要搜索,但无法在算法逻辑中实现,简单地增加它们的成本将防止不必要的搜索。有很多方法可以利用启发式来简化和通知您的路径查找,但您最大的收益将来自Jump Point Search。
编辑:Jump Point Search隐式使用与A *相同的启发式选择路径查找方向,因此您可能能够在小范围内实现启发式,但它们的成本函数不是节点的成本,而是在两个节点之间旅行的成本。(A *通常搜索相邻节点,因此节点成本和到达节点的成本之间的区别往往会崩溃。)
总结
尽管八叉树/四叉树/B树在碰撞检测中可能很有用,但它们并不适用于搜索,因为它们是基于坐标而非连接将图形分割的。将图形(词汇中的网格)分层到超级图形(区域)中是一种更有效的解决方案。
希望我有所帮助。 祝你好运!

很酷,我会看一下跳点搜索。 :) 是的,我需要在开放区域中获取节点。这种路径规划不是主要针对人工智能,而是针对人类的,许多人似乎认为我正在制作游戏(我责怪Unity标签:p)。他们决定自己想去哪里和何时去。因此,我确实希望简化搜索区域,但如果可能的话,永远不要删除节点。您应该能够在建筑物中任何地方行走。我很高兴您在摘要中分享了您的意见。这些是我想要的答案!我不认为我可以进行离线路径规划,这些“级别”并不总是预定义的... - soncis
1
一个错误的3D JPS计算出了一条错误的路径,比我的A*实现快了10倍。现在要将其纠正并进行优化。这是一个非常好的提示。谢谢。 - soncis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接