如何优化寻路算法的路径避免贴边?

目前项目的寻路实现基于A*算法,四方格,四方向。
当地图复杂起来之后,常常会出现路线贴边(最优解)的情况。但作为玩家,在游戏中的体验就变成,总是走在路边上。
举个例子:


黄色线是算法规划,红色线是理想状况。
当然不一定是红色线这样子。但相对来说,玩家一直走在路中间
大家在项目中有遇到这种情况吗?如何解决呢?

1赞

:smiley:
期待能有大佬也来一起讨论讨论

加权重,靠墙的路权重较低

1赞

正解,让靠墙的格子cost+1,或者不靠墙的格子cost-1即可,可以在读取地图后对每个格子计算

地图小的话,寻路的时候把黄色的地方设置成不可寻路状态,但是可以走动。地图大的话,又想让NPC走在路上,只能告诉NPC路在哪儿了,加减的方法根本不能绝对保证NPC在路上行走。

学过A吗?没学过看看A算法是怎么回事,再说吧

这,行吧,你厉害

cost+1后会不会导致最优解变成次优解?另一个次优解变成最优解?

是的,改变权重会使最优解变成次优解,次优解变成最优解,这不就是我们的目的吗?你的游戏,你做主。

链接:https://pan.baidu.com/s/1xxWl797hKfh6n2OA4nTH5g
提取码:ti00

草地的cost为9,沙地为10,木桩为-1(不可通行),黑地为20,地图用的tiledmap,地块自定义了distance属性,自己可以改,自己把草地的distance改成5试试。

楼主的意思应该是,存在多个最优路径时,选择一个不靠墙的。你的方法把靠墙的解变成次优来解决问题。

但是如果最优解是唯一并且靠墙,这种方法会改变最优解的步数。

加一个判定就好了呀,靠墙的格子优先不考虑 不靠墙的优先考虑最短路径

非常感谢各位大佬的回答。我来做个补充说明吧。
首先,希望路径好看(走在中间)。其次是,如果最优解和路径好看冲突的话,可以接受不是最优解(相对优即可)。
手动标识权重的话,感觉对策划来说是一项比较麻烦的工作,而且修改的时候不太友好。所以如果能以算法/其他途径解决最好。
之前尝试通过算法计算来加权重的方案(水平不够,没搞成),游戏地图比较大,可以自由行走的区域页比较复杂,没有办法合理的判定出某个路径点是否靠墙。比如:有些路很宽,有的路很窄,甚至前面宽后面窄… 还可能有个小广场啥的。

请问如何判定某个路径点是否靠墙呢?直的路肯定没问题。如果遇到带拐角的情况下,会有一个矩形区域不太好判定(之前遇到的问题)

感谢各位大佬的讲解, 我也来讲讲自己的一点见解吧, 不足之处还请大家补充 :smiley:

此处先补充一些相关知识, 以供后续有需要的朋友查阅

各位已知内容的大佬就直接跳过吧, 个人讲得实在是一般般的

1. 寻路算法:

目前常用的有 A*寻路 + 流场寻路 + JPS 寻路

1.0 关于 A* 寻路 · 个人搜集的一些在线体验网址 (欢迎大家补充)

个人感觉这两个比较直观 + 好用

1.1 [可点击] http://qiao.github.io/PathFinding.js/visual/


1.2 [可点击] https://www.redblobgames.com/pathfinding/a-star/introduction.html


2. 简介 A* 寻路的具体过程

此处公式不讨论加权重值的问题
A * 寻路的基本公式 :F = G (到起点的距离) + H (到终点的距离)

2.1 简单寻路的一个草图 (此处是八方向寻路)

2.2 寻路过程分析

接上图, 从起点寻路, 八个方向 :ABCDEFGH 八个点,
分别计算每个点里面的 F=G+H 的值 (这里采用简单的曼哈顿计算法, 不开根号)
由此可得, 最靠近终点的坐标点同侧的是 CEH 这三个点, 然后比较这三个点里面 F 值最小的,
求出的值是 E 点坐标的总值 F 值相对较小, 所以取 E 点,
距离起点都是一个格子, 所以 G=1, 距离终点的格子,
可以数一数(不跨越对角线, 就上下左右这样数).
C 点 F = 1 + 6
E 点 F = 1 + 5
H 点 F = 1 + 4 (起点阶段因为斜边比两直角边长, 这个点就排除了)
接着上面得出的路径点 E 来计算, 之前算过的格子不用再进行计算了,
E 点往右边计算 JIK 三个点, 还是用曼哈顿计算 (方便比较出一个小问题)
J 点 F = 3 + 5
I 点 F = 2 + 4
K 点 F = 3 + 3
如上计算过程, 其中 I 点和 K 点的 F 值都 == 6, 所以, 权重的计算由此而来,
此处, 可以看到 F 值相等, 但是 G 和 H 值不相等, 所以要偏向起点就用 I 点 ,偏向于去终点就用 K 点,
当然也可以引入一些数值进行动态计算, 另外要是遇到这种类型的情况,
也可以适当采用欧式算法开根号, 比如 根号二 约等于 1.4 , 此处要是用开根号,
I 点 F = 2 + ( 1.4+2) = 5.4
K 点 F = (1+1.4) + (1.4+1) = 2.4+2.4= 4.8
综上计算可得 K 点最合适, 以上过程是比较基础的内容, 大家不明白的话可以自行琢磨一下,
如有错漏之处还请各位大佬补充, :smiley:

本文示意草图 ::

3. END 不多叨叨了, 针对本文的问题, 此处我的想法如下

3.1 原本的寻路逻辑示意图

3.2 需要达到的效果 + 改造思路示意图

想法解释:
简单来说, 我的鼠标进行的这个操作就是判断是不是墙或者不可走的地方,
在计算 F 值之前, 加个简单的判断逻辑(没有计算, 纯逻辑判断),
比如八个方向的格子都需要计算 F 值, 然后在计算之前判断下每个格子的八个方向是否有墙,
如果有, 那这个格子就标记成不可走的 (就像下方我鼠标操作的一样),
对比完后再进行 F 值计算的寻路, 这样就可以规整出一个自定义的路径出来,
目前思路就是这个, 纯比对, 无多余计算, 当然有时候比较窄的地方就不太适合用这个了,
比较窄的地方必然要贴墙, 所以具体情况具体分析考虑吧,
思路效果就类似下图:

4赞

如果出现比较路宽的情况,只判断路径点是否和障碍物相邻的话,会造成仍然是贴边路径(相对贴边),举个例子:



如果要增加判断格数的话,数量不好确定,而且感觉会增加较多的性能损耗?

1赞

我先赞一下, :heart:
那这种相对贴边的情况,理想的路径是怎么样的?
性能损耗 ?那得用数据进行比对了,光想还是不妥,
要不你那边得空的时候写个简单的这个内容?
然后加点自己的理解,到性能这一块那就是代码逻辑了,
比对性能问题,目前 Js 计数器和计时的内容都不太准确,最好的测试方法就是把数量级调高测试,类似直接100或者1000个寻路算法同时计算,这样比对起来平均值比较靠谱。

1赞

理想路径:


确实应该先做出来再比较是否有性能问题,我先按照目前的思路写个demo试试。
顺便补充说明一下之前遇到的问题,同宽度情况下是比较容易算出中心路线的,但如果遇到拐角或者路面宽度改变的情况,会发生中心路线偏移。
中心线偏移举例:

橙色框为水平向道路的中心线。红色线为理想路径。

1赞

你的做法一点也不现实。楼主提供的地图路径是三格的。所以你可以这样,如果是2格或者1格的路,那你这么寻路不是路都找不到吗?应该做的是改变地块在寻路算法的优先级,而不是排除某些地块,不然得不到正确的结果。

原来是这种理想情况呀,那只能调整算法了,
你这要走出这个路径,那 A* 算法部分需要调整的还不少,
起步阶段就只能上下左右四个方向寻路了,
不能八方向寻路

正常算一遍 , 找出路径 , 然后对路径上每个点递归做优化, 判断是否太贴近墙, 太贴近的话 就从周围找一个优化的格子 代替

1赞