JS - A*寻路
算法核心
A*估值算法
寻路估值算法有非常多:常用的有广度优先算法,深度优先算法,哈夫曼树等等,游戏中用的比较多的如:A*估值
算法描述
- 对起点与终点进行横纵坐标的运算
代码实现
start: 起点坐标(point)
end: 终点坐标(point)
Math.abs(start.getX() - end.getX()) + Math.abs(start.getY() - end.getY());
算法逻辑
寻路过程中检索关联点(路径点)
对关联点分类(分为已经关联与未关联)
对未关联的点用寻路算法对其进行一次标识(每个点需要3种标识)
对比关联点的标识找出下一步的最优路径
循环上几步的操作,直到终点
算法实现
- 定义一个容器,在js中使用数组[ ],为了更好描述算法,在Array中实现几个方法
判断容器中是否存在该点:
// 根据对象判断
Array.prototype.isExistByValue = function(value) {
for (var i = 0; i < this.length; i++) {
if (value.getX() == this[i].getX() && value.getY() == this[i].getY()) {
return this[i];// 对象总是为真
}
}
return false;
}
// 根据对象中的属性值判断
Array.prototype.isExistByProperty = function(x, y) {
for (var i = 0; i < this.length; i++) {
if (x == this[i].getX() && y == this[i].getY()) {
return true;
}
}
return false;
}
移除一个点:
// 根据点的属性值移除点
Array.prototype.removeValue = function(x, y) {
for (var i = 0; i < this.length; i++) {
if (x == this[i].getX() && y == this[i].getY()) {
this.splice(i,1);
}
}
}
// 根据对象删除点
Array.prototype.remove = function(value) {
for (var i = 0; i < this.length; i++) {
if (value == this[i]) {
this.splice(i,1);
}
}
}
添加一个点:
// 根据点的坐标属性添加点到容器中
Array.prototype.add = function(x, y) {
var v = new pathUtils.locationPoint(x,y);
this.push(v);
}
根据点对象从容器中拿取该点,没有return null:
Array.prototype.getValue = function(value) {
for (var i = 0; i < this.length; i++) {
if (value.getX() == this[i].getX() && value.getY() == this[i].getY()) {
return this[i];
}
}
return null;
}
根据点的某一属性取出该点:
// 把最小F值的point找出来
Array.prototype.getValueByProperty = function() {
var minF = this[0].getF();
for (var i = 0; i < this.length; i++) {
if (minF > this[i].getF()) {
minF = this[i].getF();
}
}
for (var i = 0; i < this.length; i++) {
if (minF == this[i].getF()) {
return this[i];
}
}
return this[0];
}
- 寻路逻辑:
pathUtils.pathLogic = function(start, end, obstacArr) {
this.openList = [];
this.closeList = [];
this.openList.push(start);
while(this.openList.length != 0){
var smallF = this.openList.getValueByProperty();
this.openList.remove(smallF);
this.closeList.push(smallF);
var suround = this.getSurroundPath(smallF,obstacArr);
for (var i = 0; i < suround.length; i++) {
var tempObj = this.openList.isExistByValue(suround[i]);
if (tempObj) {
this.foundInOpenList(smallF,tempObj);
}else{
this.notFoundInOpenList(smallF,end,suround[i]);
}
}
if (this.openList.getValue(end) != null) {
this.closeList.push(end);
return this.closeList;
}
}
}
pathUtils.calcG = function(start, point) {
var G = (Math.abs(point.getX() - start.getX()) + Math.abs(point.getY() - start.getY())) == 1 ? utils.Const.PATH_HORIZONTAL_VERTICAL : utils.Const.PATH_OBLIQUITY;
return (G + point.getParentPoint().getG());
}
pathUtils.calcH = function(end, point) {
var h = Math.abs(point.getX() - end.getX()) + Math.abs(point.getY() - end.getY());
return h * utils.Const.PATH_HORIZONTAL_VERTICAL;
}
pathUtils.getSurroundPath = function(point, obstacArr) {
var surroundArr = [];
for (var i = point.getX() - 1; i <= point.getX() + 1; i++) {
for (var j = point.getY() -1; j <= point.getY() + 1; j++) {
if (this.closeList.isExistByProperty(i,j)) continue;
if (obstacArr && obstacArr.length && obstacArr.isExistByProperty(i,j)) continue;
surroundArr.add(i,j);
}
}
return surroundArr;
}
pathUtils.foundInOpenList = function(tempPoint, point) {
var G = this.calcG(tempPoint,point);
if (G < point.getG()) {
point.setParentPoint(tempPoint);
point.setG(G);
point.calcF();
}
}
pathUtils.notFoundInOpenList = function(tempPoint, end, point) {
point.setParentPoint(tempPoint);
point.setG(this.calcG(tempPoint,point));
point.setH(this.calcH(end,point));
point.calcF();
this.openList.push(point);
}
算法细节
需要注意的几点
点对象中标识G的计算
点对象中标识H的计算
点对象已经被关联过
点对象未被关联过
要点突破
当前起点与终点的parent是为null(没有父节点的概念)
G值计算:
相对于起点G值一直增大(横竖走一步消耗为10,斜向走一步消耗为14)
G值有8个方向需要计算
G值总是越靠近终点值越小
H值计算:
相对于起点H值一直减小(离终点近一步-10,离终点远一步+10)
H值有4个方向需要计算
H值相对于终点是不变的
点已被关联过:
如果某个相邻方格已经在openList里了, 检查如果用新的路径 (就是经过最优点的路径) 到达它的话, G值是否会更低一些
如果新的G值更低, 那就把它的parent改为目前选中的方格, 然后重新计算它的 F 值和 G 值 (H 值不需要重新计算, 因为对于每个方块, H 值是不变的)
如果新的 G 值比较高, 就说明经过最优点再到达该相邻点不是一个明智的选择, 因为它需要更远的路, 这时我们什么也不做
点未被关联过:
- 检查它所有相邻并且可以到达 (障碍物和closeList的方格都不考虑) 的方格. 如果这些方格还不在openList里的话, 将它们加入openList, 计算这些方格的 G, H 和 F 值各是多少, 并设置它们的parent为该最优点
算法总结
A*算法并非是寻路中最好的算法,但由于其实现简单所以在工程中大量使用
A*寻路整体不是非常难,只要注意细节就不会出现bug
JS - A*寻路的更多相关文章
- javascript的Astar版 寻路算法
去年做一个模仿保卫萝卜的塔防游戏的时候,自己写的,游戏框架用的是coco2d-html5 实现原理可以参考 http://www.cnblogs.com/technology/archive/2011 ...
- js实现A*寻路算法
这两天在做百度前端技术学院的题目,其中有涉及到寻路相关的,于是就找来相关博客进行阅读. 看了Create Chen写的理解A*寻路算法具体过程之后,我很快就理解A*算法的原理.不得不说作者写的很好,通 ...
- PathFinding.js 寻路类神器
最近有打算写个迷宫玩玩,无意中发下了这个库,很强大!又是开源在github的,并且有一个相当酷的demo.这个库不仅支持浏览器端的运行,而且可以运行在node.js上.怎么用到服务器上这里就不涉及了, ...
- js算法之寻路
A*寻路算法 算法流程说明: 说明:起始节点记作S,目标节点记作E,对于任意节点P,从S到当前节点P的总移动消耗记作GP,节点P到目标E的曼哈顿距离记作HP,从节点P到相邻节点N的移动消耗记作DPN, ...
- 【JS】 Javascript与BOM的互动 寻路
JS BOM 之前提到过JS和DOM之间的互动方法.而BOM(Browser Object Module)是浏览器的对象模型,它也可以和JS进行互动.也就是说,JS还可以和浏览器进行互动.因为现代主流 ...
- 【JS】 Javascript与HTML DOM的互动 寻路
JS HTML DOM DOM的全程是Document Object Module,即文档对象模型.一般来说,当一个页面被加载时,浏览器会在内部创建一个当前文档的DOM.就像用python的Etree ...
- JS算法之A*(A星)寻路算法
今天写一个连连看的游戏的时候,接触到了一些寻路算法,我就大概讲讲其中的A*算法. 这个是我学习后的一点个人理解,有错误欢迎各位看官指正. 寻路模式主要有三种:广度游戏搜索.深度优先搜索和启发式搜索. ...
- JS中实现A*算法寻路
<html><head><title>use A* to find path...</title></head><body style ...
- unity自带寻路Navmesh入门教程(一)
说明:从今天开始,我阿赵打算写一些简单的教程,方便自己日后回顾,或者方便刚入门的朋友学习.水平有限请勿见怪.不过请尊重码字截图录屏的劳动,如需转载请先告诉我.谢谢! unity自从3.5版本之后,增加 ...
随机推荐
- Struts2框架(5)---result结果集
result结果集 上一篇文章主要讲Struts2框架(4)---Action类访问servlet这篇主要讲result结果集 在Struts.xml中的result元素指的是:指定动作类的动作方法执 ...
- WeMall商城系统的Android app商城中的wemall-mobile代码
wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改. [适合研究学习,支持wemall3.x版本] 1.快 ...
- UI 事件处理
一 > 事件的基本概念 事件概述 : UIEvent ( [ɪ’vent]事件 ) 事件,是由硬件捕捉的一个表示用户操作设备的对象 分三类 : 触摸事件 ,晃动事件 ,远程控制事件 触摸事 ...
- C#"曾经的字符串数组"string[] array=new string[]{"**","****"};
写博客是一件很伟大的事情,尤其是也牛逼的博客,因为它能帮助需要的人,更能使自己对知识有一个更为深刻的理解! 欢迎关注我的博客! 字符串操作(取当前时间) string time=convert.tos ...
- SQL一次查出相关类容避免长时间占用表(下)
/* server: db: EDI */ -- 以下案例多次查询同一张表,仅有Name条件不同 --可以使用一次查出相关类容避免长时间占用表 USE EDI GO DECLARE @FileType ...
- Maven使用说明
maven的作用. Maven 是一个项目管理和构建自动化工具.可以方便我们导入jar包. maven的安装. 要想安装maven,首先你需要安装jdk,并且配置jdk环境变量.右键点击计算机,选择属 ...
- UT源码 005
NextDate函数问题 NextDate函数说明一种复杂的关系,即输入变量之间逻辑关系的复杂性 NextDate函数包含三个变量month.day和year,函数的输出为输入日期后一天的日期. 要求 ...
- (15)IO流之File
File类用封装了一个文件夹或者文件的所有属性. File类的构造方法: File(String pathname) 指定文件或者文件夹的路径创建一个File文件 File(File parent, ...
- ng-clip angualr 的copy功能
每次写博客都想由衷的给我的老大膜拜一番!以前刚开始做angular的项目的时候就有说要有点击复制的功能因为当时菜啊,不懂啊.也就没做,今天老大又给了我一个资料!“ng-clip”.跟着老大最大的收获就 ...
- 实验楼-2-Linux基础快捷键
终端:本质上对应着Linux上的/dev/tty设备 shell:打开终端,shell则自动打开 可以在终端直接输入: echo "hello world" /*shell程序自动 ...