一种非常简单有效的基于格子的寻路算法

这是之前手游项目中琢磨出来的一个简单易行, 同时感觉比较高效的一个寻路算法.  当然有一个前提, 是基于格子的寻路, 你的格子可以是正方形, 六边形等. 总之, 从一个格子移动到旁边任何一个格子的代价是相等的, 也就是步数都是一, 这个算法可能也适应于其它场景, 当然我对寻路算法也没什么研究, 仅仅是解决了我所遇到的问题.

这是一个最短路径寻路算法.

地图如下, 6 * 6,  当时项目中实际的地图尺寸为5 * 14, 没有关系. 原理是一样的. 

假设我们要从1.2(x = 1, y = 2)移动到5.4, 图中的红色部分.

《一种非常简单有效的基于格子的寻路算法》

如果地图上没有任何障碍, 那么其中一条(有多条)最短路径可能是 1.2–>2.2–>3.3–>4.4–>5.4, 一共是4步. 算法的实现步聚如下:

1. 开放列表(存放等待扫描其周围的格子) .

将1.2加入到开放列表. 扫描它的周围, 理论上, 如果你是四边形的格子, 那么任何一个格子的周围都有8个格子(不考虑边界), 扫描完后, 记下这8个格子到1.2这个座标的距离, 都是一步, 所以下面这个图中标记的全是1, 这是第一轮扫描.

《一种非常简单有效的基于格子的寻路算法》

2. 将1.2从开放列表中移除(它已经扫描过了), 并将刚才扫描的8个格子加入到开放列表.

3. 扫描这8个格子的周围, 将它们周围未扫描过(已扫描过的不要参与)的格子标记距离为2, 这是第二轮扫描, 结果如下.

《一种非常简单有效的基于格子的寻路算法》

4. 依次类推, 扫描完剩余的格子, 这里的规律是, 第一轮扫描的格子的距离离出发点一定是1, 第二轮扫描的离出发点一定是2.  第三轮一定是3. 直到扫完所有的格子, 最终的结果如下:

《一种非常简单有效的基于格子的寻路算法》

5. 好了, 如何得到最短路径呢? 

关闭列表(被选择到最终路径中的格子).

我们将5.4加入到关闭列表. 并扫描它周围每一个格子所标记的步数(从起点1.2过来的步数),  会得到六个格子, 有两个格子(5.3, 5.5)到1.2有四步, 另外有三个格子到1.2只有三步, 换句话说, 在这里我们至少有3条最短的路可以回到1.2, 选择任何一条都可以, 如下图.

《一种非常简单有效的基于格子的寻路算法》

6. 随便(如果你想角色移动的比较合符自然规律的话, 不能随便选)选一个, 我们就选4.4, 也就是5.4正左边的这个格子, 将它加入到关闭列表, 然后再扫描4.4周围的格子, 同样找出到1.2需要最少步数的格子, 这里有两个(3.4, 3.3), 如下图.

《一种非常简单有效的基于格子的寻路算法》

7. 还是随便选一个, 3.3, 继续扫描,  得到2.2和3.3两个距离1.2的步数都为1的格子, 如下:

《一种非常简单有效的基于格子的寻路算法》

8. 再随便选一个2.2, 再往下扫, 就能碰到1.2了, 接着就不用再扫了, 这个时候, 关闭列表中已经存在一条最短路径了. 是: 5.4–>4.4->>3.3–>2.2–>1.2

9. 有人要问, 为什么是从终点5.4向起点1.2反向扫描呢? ^:^

10. 有障碍的情况下, 如何处理? 如下图中, 4.1, 4.2,4.3, 4.4, 4.5都无法通过.

《一种非常简单有效的基于格子的寻路算法》

 其实还是按照之前的扫描方式就可以了, 只是当碰到障碍时不用标记, 最终扫描的结果如下, 一样可以得到最短路径.

《一种非常简单有效的基于格子的寻路算法》

11. 优化, 这个算法存在一些优化的可能, 例如.

a). 如果1.2至5.4方向的前一排, 即2.0 ~ 2.5全部无障碍时, 我们就可不必扫描1.2身后所有格子, 因为这时不必绕路. 如果1.2在地图中间, 那将有一半的格子不用参与计算.

b). 某些条件下是否可以扫描到5.4之时, 对身后的格子不再扫描? 这样, 如果5.4在地图中间, 那么也将有一半的格子不用参与计算.

 请寻路算法高手不吝赐教, 另外, 上面有几张图有个小错误: 0.5这个格子应该标注为(3), 而不是(2). 

点赞