利用跳点搜索算法,优化A*寻路

在游戏中寻路是无处不在的。最著名的寻找最短路径算法莫过与A*算法,实现方式有很多种,重要的是我们要掌握其原理。

在本教程中,我们将介绍一种相对较新的方法搜索——基于网格的世界的跳点的搜索,可以加速A*寻路算法。效率提升那是大大的。

我假设读者已经明白A*算法的原理。如果你对A星寻路还不是很了解的话,请网上自行另找资料

好的,下面进入正题,开始讲解Jump Point Search!(以下简称JPS)

下面开始讲解原理

常规A*算法,是向相邻的格子中搜索可能的“最近节点”,然后把所有的“最近节点”连接起来,既为最终解。至于说怎样的节点才是“最近节点”,本篇不做介绍,因为我前面已经设定了读者是已经明白A*算法的原理的了。

问题的关键,就在于,我们一定要逐格逐格的去搜索吗?随着格子密集度提升,时间复杂度也将大幅提升。

那么我们如何去优化呢?

很简单,对于大片的可行走区域,他们之间的任何一点都是可联通的,我们可以省去这部分格子的“最近节点”搜索,这将是很大一部分的搜索的运算了。我们只需要找出一些相关的控制点,然后通过控制点之间的连通,省去大部分无谓的“寻找最近节点”的运算。

具体思路如下:

1 生成/摆放好 凸多边形障碍物

2 “扩展”多边形 扩展的大小取决于 寻路者的大小

3 将地图中所有联通点(以扩展后的多边形为主)构成一张”图”

4 将寻路者的起点和目标点作为”临时节点”加入到3)中生成的图里

5 在图中寻路. 寻路后将之前的起点移除.

下面我们举个例子:

1、有如下一张地图,途中黑色填充为不可行走区
jsp2
2、 “扩展”多边形 扩展的大小取决于 寻路者的大小,如图中细线部

jsp2

3、将地图中所有联通点(以扩展后的多边形为主)构成一张”图”
jsp2

4 、将寻路者的起点和目标点作为”临时节点”加入到3)中生成的图里
jsp2

5、基于图中的“控制点” ,在图中寻路.

5.1、寻路第一步,将起始点作为搜索点,在与其相邻的控制点中,找到可能的“最近节点”,如图所示,最粗的两条线的交点,就是我们要找的“最近节点”,因为其深绿色线段+浅绿色线段的长度之和,是最短的。这也是A*寻路的基本思路。
jsp2

5.2、寻路第二步,把上一步寻找到的“最近节点”,作为新的搜索点,然后重复同样的判断,找到新的新的“最近节点”,如图所示,红色的点,就是我们要找的新的“最近节点”
jsp2

5.3、寻路第N步,重复同样的算法,寻找新的可能的“最近节点”,直到找到“终点”。如下图,深绿色的路线,就是我们寻路结果。
jsp2

总结:

看到这里,我想大家一定都懂了,也肯定明白了,为什么利用JPS算法能够大大提高A*寻路的效率。因为它省去了一些无谓的判断节点。当然它是需要在寻路之前,开销一些空间和时间去进行地图的预处理。不过这点开销,在后面寻路算法中又大大地赚了回来。

### 双向搜索算法A*算法的关系 双向搜索路径规划(Bidirectional JPS)确实是对经典A*算法的一种改进版本[^2]。这种改进主要体现在两个方面: 1. **双向搜索机制**:不同于传统的单向A*算法仅从起出发进行搜索,双向JPS采用从起和终同时发起搜索的方式。这种方式减少了不必要的探索范围,从而提高了搜索效率。 2. **策略的应用**:在标准的A*基础上引入了(Jump Point)的概念,即只关注那些可能成为最短路径一部分的关键节(称为“”),而忽略其他不可能构成解的部分网格单元。这种方法进一步加速了搜索过程并降低了计算复杂度。 因此,可以说双向搜索不仅继承了A*的核心思想—基于代价估计来指导搜索方向;而且还通过上述两项关键技术实现了对原版A*性能的有效提升。 ```python def bidirectional_jps(start, goal): open_list_start = PriorityQueue() open_list_goal = PriorityQueue() # 初始化起始状态 start_node = Node(start) goal_node = Node(goal) open_list_start.put((0, start_node)) open_list_goal.put((0, goal_node)) while not open_list_start.empty() and not open_list_goal.empty(): current_f_score_start, current_node_start = open_list_start.get() current_f_score_goal, current_node_goal = open_list_goal.get() if heuristic(current_node_start.position, current_node_goal.position) == 0: return reconstruct_path(meet_point_in_middle) neighbors_start = jump_search(current_node_start) for neighbor in neighbors_start: tentative_gScore = gScores[current_node_start] + dist_between(current_node_start, neighbor) if tentative_gScore < gScores[neighbor]: cameFrom[neighbor] = current_node_start gScores[neighbor] = tentative_gScore fScore := tentative_gScore + heuristic(neighbor, end) if neighbor not in open_set: open_list_start.put(fScore, neighbor) # 对于目标端也执行相同的操作... raise ValueError('No path found') ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值