深入理解js A*寻路算法原理与具体实现过程


Posted in Javascript onDecember 13, 2018

本文实例讲述了js A*寻路算法原理与具体实现过程。分享给大家供大家参考,具体如下:

这两天研究了下 A* 寻路算法, 主要学习了这篇文章, 但这篇翻译得不是很好, 我花了很久才看明白文章中的各种指代. 特写此篇博客用来总结, 并写了寻路算法的代码, 觉得有用的同学可以看看. 另外因为图片制作起来比较麻烦, 所以我用的是原文里的图片.

当然寻路算法不止 A* 这一种, 还有递归, 非递归, 广度优先, 深度优先, 使用堆栈等等, 有兴趣的可以研究研究~~

简易地图

深入理解js A*寻路算法原理与具体实现过程

如图所示简易地图, 其中绿色方块的是起点 (用 A 表示), 中间蓝色的是障碍物, 红色的方块 (用 B 表示) 是目的地. 为了可以用一个二维数组来表示地图, 我们将地图划分成一个个的小方块.

二维数组在游戏中的应用是很多的, 比如贪吃蛇和俄罗斯方块基本原理就是移动方块而已. 而大型游戏的地图, 则是将各种"地貌"铺在这样的小方块上.

寻路步骤

1. 从起点A开始, 把它作为待处理的方格存入一个"开启列表", 开启列表就是一个等待检查方格的列表.

2. 寻找起点A周围可以到达的方格, 将它们放入"开启列表", 并设置它们的"父方格"为A.

3. 从"开启列表"中删除起点 A, 并将起点 A 加入"关闭列表", "关闭列表"中存放的都是不需要再次检查的方格

深入理解js A*寻路算法原理与具体实现过程

图中浅绿色描边的方块表示已经加入 "开启列表" 等待检查. 淡蓝色描边的起点 A 表示已经放入 "关闭列表" , 它不需要再执行检查.

从 "开启列表" 中找出相对最靠谱的方块, 什么是最靠谱? 它们通过公式 F=G+H 来计算.

F = G + H

    G 表示从起点 A 移动到网格上指定方格的移动耗费 (可沿斜方向移动).

    H 表示从指定的方格移动到终点 B 的预计耗费 (H 有很多计算方法, 这里我们设定只可以上下左右移动).

深入理解js A*寻路算法原理与具体实现过程

我们假设横向移动一个格子的耗费为10, 为了便于计算, 沿斜方向移动一个格子耗费是14. 为了更直观的展示如何运算 FGH, 图中方块的左上角数字表示 F, 左下角表示 G, 右下角表示 H. 看看是否跟你心里想的结果一样?

从 "开启列表" 中选择 F 值最低的方格 C (绿色起始方块 A 右边的方块), 然后对它进行如下处理:

4. 把它从 "开启列表" 中删除, 并放到 "关闭列表" 中.

5. 检查它所有相邻并且可以到达 (障碍物和 "关闭列表" 的方格都不考虑) 的方格. 如果这些方格还不在 "开启列表" 里的话, 将它们加入 "开启列表", 计算这些方格的 G, H 和 F 值各是多少, 并设置它们的 "父方格" 为 C.

6. 如果某个相邻方格 D 已经在 "开启列表" 里了, 检查如果用新的路径 (就是经过C 的路径) 到达它的话, G值是否会更低一些, 如果新的G值更低, 那就把它的 "父方格" 改为目前选中的方格 C, 然后重新计算它的 F 值和 G 值 (H 值不需要重新计算, 因为对于每个方块, H 值是不变的). 如果新的 G 值比较高, 就说明经过 C 再到达 D 不是一个明智的选择, 因为它需要更远的路, 这时我们什么也不做.

深入理解js A*寻路算法原理与具体实现过程

如图, 我们选中了 C 因为它的 F 值最小, 我们把它从 "开启列表" 中删除, 并把它加入 "关闭列表". 它右边上下三个都是墙, 所以不考虑它们. 它左边是起始方块, 已经加入到 "关闭列表" 了, 也不考虑. 所以它周围的候选方块就只剩下 4 个. 让我们来看看 C 下面的那个格子, 它目前的 G 是14, 如果通过 C 到达它的话, G将会是 10 + 10, 这比 14 要大, 因此我们什么也不做.

然后我们继续从 "开启列表" 中找出 F 值最小的, 但我们发现 C 上面的和下面的同时为 54, 这时怎么办呢? 这时随便取哪一个都行, 比如我们选择了 C 下面的那个方块 D.

深入理解js A*寻路算法原理与具体实现过程

D 右边已经右上方的都是墙, 所以不考虑, 但为什么右下角的没有被加进 "开启列表" 呢? 因为如果 C 下面的那块也不可以走, 想要到达 C 右下角的方块就需要从 "方块的角" 走了, 在程序中设置是否允许这样走. (图中的示例不允许这样走)

深入理解js A*寻路算法原理与具体实现过程

就这样, 我们从 "开启列表" 找出 F 值最小的, 将它从 "开启列表" 中移掉, 添加到 "关闭列表". 再继续找出它周围可以到达的方块, 如此循环下去...

那么什么时候停止呢? —— 当我们发现 "开始列表" 里出现了目标终点方块的时候, 说明路径已经被找到.

如何找回路径

深入理解js A*寻路算法原理与具体实现过程

如上图所示, 除了起始方块, 每一个曾经或者现在还在 "开启列表" 里的方块, 它都有一个 "父方块", 通过 "父方块" 可以索引到最初的 "起始方块", 这就是路径.

将整个过程抽象

把起始格添加到 "开启列表"

do
{
       寻找开启列表中F值最低的格子, 我们称它为当前格.
       把它切换到关闭列表.
       对当前格相邻的8格中的每一个
          if (它不可通过 || 已经在 "关闭列表" 中)
          {
                什么也不做.
           }
          if (它不在开启列表中)
          {
                把它添加进 "开启列表", 把当前格作为这一格的父节点, 计算这一格的 FGH
          if (它已经在开启列表中)
          {
                if (用G值为参考检查新的路径是否更好, 更低的G值意味着更好的路径)
                    {
                            把这一格的父节点改成当前格, 并且重新计算这一格的 GF 值.
                    }
} while( 目标格已经在 "开启列表", 这时候路径被找到)

如果开启列表已经空了, 说明路径不存在.

最后从目标格开始, 沿着每一格的父节点移动直到回到起始格, 这就是路径.

主要代码

程序中的 "开启列表" 和 "关闭列表"

List<Point> CloseList;
List<Point> OpenList;

Point 类

public class Point
{
  public Point ParentPoint { get; set; }
  public int F { get; set; } //F=G+H
  public int G { get; set; }
  public int H { get; set; }
  public int X { get; set; }
  public int Y { get; set; }
  public Point(int x, int y)
  {
    this.X = x;
    this.Y = y;
  }
  public void CalcF()
  {
    this.F = this.G + this.H;
  }
}

寻路过程

public Point FindPath(Point start, Point end, bool IsIgnoreCorner)
{
  OpenList.Add(start);
  while (OpenList.Count != 0)
  {
    //找出F值最小的点
    var tempStart = OpenList.MinPoint();
    OpenList.RemoveAt(0);
    CloseList.Add(tempStart);
    //找出它相邻的点
    var surroundPoints = SurrroundPoints(tempStart, IsIgnoreCorner);
    foreach (Point point in surroundPoints)
    {
      if (OpenList.Exists(point))
        //计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F
        FoundPoint(tempStart, point);
      else
        //如果它们不在开始列表里, 就加入, 并设置父节点,并计算GHF
        NotFoundPoint(tempStart, end, point);
    }
    if (OpenList.Get(end) != null)
      return OpenList.Get(end);
  }
  return OpenList.Get(end);
}

完整实例代码点击此处本站下载

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
JavaSript中变量的作用域闭包的深入理解
May 12 Javascript
jQuery中get()方法用法实例
Dec 27 Javascript
jQuery手机浏览器中拖拽动作的艰难性分析
Feb 04 Javascript
jQuery获取URL请求参数的方法
Jul 18 Javascript
js操作XML文件的实现方法兼容IE与FireFox
Jun 25 Javascript
关于两个jQuery(js)特效冲突的bug的解决办法
Sep 04 Javascript
Jquery EasyUI Datagrid右键菜单实现方法
Dec 30 Javascript
Angular4 反向代理Details实践
May 30 Javascript
使用D3.js构建实时图形的示例代码
Aug 28 Javascript
快速解决layui弹窗按enter键不停弹窗的问题
Sep 18 Javascript
LayUi数据表格自定义赋值方式
Oct 26 Javascript
vscode 使用Prettier插件格式化配置使用代码详解
Aug 10 Javascript
Vue.js上传图片到阿里云OSS存储的方法示例
Dec 13 #Javascript
JS/HTML5游戏常用算法之路径搜索算法 随机迷宫算法详解【普里姆算法】
Dec 13 #Javascript
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【凹多边形的分离轴检测算法】
Dec 13 #Javascript
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【矩形情况】
Dec 13 #Javascript
详解Express笔记之动态渲染HTML(新手入坑)
Dec 13 #Javascript
js实现黑白div块画空心的图形
Dec 13 #Javascript
JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【圆形情况】
Dec 13 #Javascript
You might like
深入探讨:Nginx 502 Bad Gateway错误的解决方法
2013/06/03 PHP
PHP封装分页函数实现文本分页和数字分页
2014/10/23 PHP
PHP GD库生成图像的几个函数总结
2014/11/19 PHP
几个实用的PHP内置函数使用指南
2014/11/27 PHP
php实现无限级分类(递归方法)
2015/08/06 PHP
PHP实现获取文件mime类型多种方法解析
2020/05/28 PHP
javascript 打开页面window.location和window.open的区别
2010/03/17 Javascript
ExtJs使用IFrame的实现代码
2010/03/24 Javascript
js实现通用的微信分享组件示例
2014/03/10 Javascript
浅谈Javascript的静态属性和原型属性
2015/05/07 Javascript
js实现div层缓慢收缩与展开的方法
2015/05/11 Javascript
jquery+html5时钟特效代码分享(可设置闹钟并且语音提醒)
2020/03/30 Javascript
关于Bootstrap弹出框无法调用问题的解决办法
2016/03/10 Javascript
js 获取范围内的随机数实例代码
2016/08/02 Javascript
jQuery的deferred对象使用详解
2016/09/25 Javascript
对于input 框限定输入值为浮点型的js代码
2017/09/25 Javascript
Vue+Typescript中在Vue上挂载axios使用时报错问题
2019/08/07 Javascript
node.js实现简单的压缩/解压缩功能示例
2019/11/05 Javascript
python统计cpu利用率的方法
2015/06/02 Python
Python实现大文件排序的方法
2015/07/10 Python
深入理解NumPy简明教程---数组2
2016/12/17 Python
python+VTK环境搭建及第一个简单程序代码
2017/12/13 Python
对python操作kafka写入json数据的简单demo分享
2018/12/27 Python
Python设计模式之桥接模式原理与用法实例分析
2019/01/10 Python
python实现简单五子棋游戏
2019/06/18 Python
python实现滑雪者小游戏
2020/02/22 Python
python drf各类组件的用法和作用
2021/01/12 Python
线程的基本概念、线程的基本状态以及状态之间的关系
2012/10/26 面试题
婚礼证婚人证婚词
2014/01/08 职场文书
小学生期末自我鉴定
2014/01/19 职场文书
幼儿园运动会口号
2014/06/07 职场文书
小学红领巾广播稿(3篇)
2014/09/13 职场文书
法人授权委托书样本
2014/09/19 职场文书
2014年新教师工作总结
2014/11/08 职场文书
2015年体检中心工作总结
2015/05/27 职场文书
web前端之css水平居中代码解析
2021/05/20 HTML / CSS