我正在制作一张10,000 x 10,000地图的游戏
我希望用户能够设置位置并让计算机立即找到最佳路径
但是,由于地图是10,000乘10,000,有100,000,000个节点,并且通过传统方法(例如A *或Dijkstra)找到这条路径需要大量内存和很长时间。
所以我的问题是:我怎样才能找到最好的路径?
我正在考虑的算法将世界划分为100个部分,每个部分有1,000,000个节点。然后将每个部分分成100个小节。这将重复进行,直到每个子部分包含100个节点。然后,算法将找到段的最佳路径,然后是子段,然后是子子段,直到找到最佳节点集。这会有效吗?还有更好的方法吗?
我也在考虑跳点搜索,但我不知道,只是发现它无法做到这一点很痛苦。
编辑:我试图添加A *。但是,运行大约需要5秒钟,比理想时间长约4秒。
答案 0 :(得分:8)
由于地图为10.000 x 10.000,因此节点数为100.000.000。使用A *的简单实现是不切实际的,当然也不会使游戏在地图中可扩展。
我建议您使用以下解决方案,这基本上就是您的想法:
HPA * (分层路径A *)。此方法创建不同的地图层次结构。您可以通过说每个100x100像素的块是一个区域来自动化该过程。然后,对于每个块,我们需要找到相邻的块以及每个块的入口和出口的位置。 如果两个块之间的连接不仅仅是一个节点,那么我们使用两个节点来表示问题。此图片说明了我们正在尝试构建的新图表。 (黑色=障碍物和灰色是块之间的连接节点)。
这种方法提供了良好的效果,从使用游戏Baldur's Gate的地图执行可以看出,每个块都是10x10。
欲了解更多信息,请阅读Nathan Sturtevant撰写的这篇文章(他是游戏中最成功的寻路研究员之一)。 https://skatgame.net/mburo/ps/path.pdf
有关HPA的解释,请查看Sturtevant的讲座(HPA的最小比例为43:50)。 https://www.youtube.com/watch?v=BVd5f66U4Rw
此外,如果您想查看HPA *的运行情况,请查看Sturtevant制作的视频: https://www.youtube.com/watch?v=l7YQ5_Nbifo
答案 1 :(得分:0)
我对问题陈述的初步理解如下。地图上有预定义的终端位置。用户在地图上选择一个位置,并且必须找到最接近这些位置的最佳/最短路径。
如果我的理解是正确的,那么您可以通过BFS算法的单个应用程序预先计算地图上所有位置的最短路径。您可以使用每个节点仅2位有效地存储该信息(与每个节点关联的值将告知您必须从该节点移动到哪个方向以保持最短路径。)
但是,正如tobias_k所述,问题的定义可能不同 - 玩家在地图上选择一个任意位置,并且必须找到从当前位置到该位置的最佳路径。如果
,可以再次使用先前描述的方法然后执行已经描述的算法以找到从地图上的任何位置到以玩家当前位置为中心的小圆周的最短路径。然后在短时间内可以使用数据快速将准最短路径路由到地图上的任何位置。当玩家在移动时太靠近该圈的边界时,该算法会先抢先执行该玩家的新位置。
这种方法的缺点是它消耗了大量的CPU资源。优点是简单。
答案 2 :(得分:0)
这将比评论中的内容长一些,因此是一个答案。
您的设置需要澄清。 10,000x10,000都很好,但这句话不是:
因为地图是10,000乘10,000,所以有100,000,000个节点
为什么每个坐标系单位都有1个节点?这不是节点寻路的工作方式,而是节点应该更稀疏,并且通过它们的存在来描述沿路径的各个(稀疏)点。在节点之间,对象通过其他方式处理移动。在最坏的情况下(如果没有障碍物),网格寻路系统可能有100,000,000个点,但是当Q提到节点时,我假设这是关于节点寻路的。
100,000,000个节点
如果是int32,那么100,000,000个节点是381兆字节的内存,如果是float64则是763 mb。此外,还有节点连接。我不知道如何在你的情况下设置这些,但每个连接需要2个整数,比如每个2个字节。 IE浏览器。如果有与节点一样多的连接,则需要另外381 mb。总而言之,我们最终得到的图形数据接近1TB,我声称肯定有些错误。
如果我们仍然有一个巨大的节点图/一个巨大的区域,如何解决这个问题?我可能会通过创建更大的象限来简化(如你所提到的)。然而,每个象限仅沿着4个边缘保持节点 - 象限内的所有节点将被直线替换。这样,就可以解决每个象限的进入/退出点。这将是一个单独的节点图,用于粗略计算。然后,在象限内,人们总是只在时间加载该象限的内部节点图。 Ofc会有某种错误,但是,嘿,这是真的,对吗?如果这是关于人类行为的,那么它并不总是完全优化。
预计算,缓存,速度,小数据是游戏编码中的关键词。
答案 3 :(得分:0)
所以即使在n平方n的地图上可能有n^4
个最短路径。存储所有路径并不一定需要O(n^4)
空间。这个想法是,给定地图上的两个不同目标位置及其最短路径树,而不是这两个点在地图上越近,它们的最短路径树将具有更常见的元素。当使用平面地图(如带障碍物的网格)时尤其如此。
因此,我们的想法是只为一小组目标位置存储一些完整的最短路径树(甚至可能只有一个目标位置)。对于其余的目标位置,仅存储其最短路径树与先前存储的最短路径树之一的差异。
然后,找到从一个位置到目标的最短路径的算法是加载完全存储的最短路径树,然后对其应用一些差异以获得目标位置的最短路径树。然后,只需要在O(n^2)
复杂度的最短路径树上找到当前玩家位置。
关于存储最短路径树及其差异需要多少存储空间,我没有任何确凿的事实,但这可能在O(n^2 log(n^2))
范围内。加载一个并对差异进行应用可能只有O(n^2)
的时间复杂度。
目标位置的最短路径树表示从地图上每个位置到目标位置的所有最短路径。
此解决方案还可以将使用过的最短路径树保留在内存中,并根据需要应用差异,以便使用新的最短路径树。然后,获取最短路径树的复杂性不受地图大小的约束,而只受要应用的差异大小的约束。这种情况可能适用于原版Sacred或暗黑破坏神等游戏。
答案 4 :(得分:0)
如果您的地图具有统一的权重(当然除了障碍物),您可以使用以下任一方面获得更好的表现:
将网格预处理为图形的算法,将大的空白空间折叠为单个节点。导航网格将可遍历区域分成凸多边形,每个凸多边形可以在一个步骤中遍历。 L1 path finder将障碍分组在一起,将它们缩小为可见性图,计算出该障碍。
不扩展每个节点的算法。 Jump-point search利用不同路径之间的对称性,仅扩展与障碍物相邻的节点,而A *将沿最短路径扩展每个节点。
答案 5 :(得分:0)
高级概念可能是找到开始和结束的点 - 比如点(0,0)和点(10000,10000) - 并对从开始到结束的路径进行初步猜测(在此如果它会沿着对角线向上和向右运行)然后开始检查它是否可以成功到达那里(如果该路径上有障碍物)。如果然后以编程方式选择相似的路径,或者交替找到路径失败的位置并从那里开始并尝试迭代直到它工作,它可能不是100%最快,但你会得到比找到每一种可能的方式更好的结果,然后从中推断出最短的路径。
实施
答案 6 :(得分:0)