A*寻路算法 (cocos2d-js详细代码)
看了几天的A*算法,感觉要成为一个游戏开发者,有必要把这个著名的算法拿到手。
网上有此算法的代码片段,但主要还是些模板类的伪代码,所以想分享一段完整的A*算法代码供大家更好的理解!(这里使用的是js语言和cocos2d游戏引擎)
对于A*算法概念性的描述,请看这里,本篇主要以代码为主。
下面是我的学习成果,有晦涩和需改进的地方欢迎吐槽!
var A_STAR_DISTANCE = 7; //像素大小,越小越精确,同时越耗时
var A_STAR_G_EXPEND_MIN = 10; //上下左右G值消耗数
var A_STAR_G_EXPEND_MAX = 14; //斜角G值消耗数 var HelloWorldLayer = cc.Layer.extend({
sprite:null, //角色
aStarPathArray:[], //最终角色要行走的路径
aStarBarrierArray:[], //地图障碍物
testNumber:1,
ctor:function () {
//////////////////////////////
// 1. super init first
this._super();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// ask director the window size
var size = cc.director.getWinSize(); this.sprite = cc.Sprite.create(res.Plane_png); //角色初始化
this.sprite.attr({
x: 150,
y: 50,
rotation: 90
});
this.addChild(this.sprite, 0); var barrier1 = cc.rect(200,50,50,350); //绘制障碍物
var barrier2 = cc.rect(250,50,350,50);
var barrier3 = cc.rect(250,350,350,50);
this.aStarBarrierArray.push(barrier1);
this.aStarBarrierArray.push(barrier2);
this.aStarBarrierArray.push(barrier3); var drawBarrier = cc.DrawNode.create(); //在屏幕上显示障碍物
this.addChild(drawBarrier, 10);
var vertices = [cc.p(200,50),cc.p(600,50),cc.p(600,100),cc.p(250,100),cc.p(250,350),cc.p(600,350),cc.p(600,400),cc.p(200,400)];
drawBarrier.drawPoly(vertices,null,2,cc.color(255,0,0,255)); if ('mouse' in cc.sys.capabilities)
cc.eventManager.addListener({
event: cc.EventListener.MOUSE,
onMouseUp:function(event){
if(event.getButton() != undefined)
{
var t = new Date().getTime();
event.getCurrentTarget().getStartAndEndPoint(event); //A*算法开始
cc.log("算法耗时:"+(new Date().getTime() - t)+"ms"); //计算起点到终点的算法耗时
}
}
}, this); return true;
},
getStartAndEndPoint:function (event) { //得到起始点和终点坐标
var sp = {coordX:parseInt(this.sprite.x,10),coordY:parseInt(this.sprite.y,10)};
var ep = {coordX:parseInt(event.getLocation().x,10),coordY:parseInt(event.getLocation().y,10)};
var endPointIsObstacle = false; //判断终点是否在障碍物上,是的话就提示路径走不了
for (var theBarrierIndex=0; theBarrierIndex<this.aStarBarrierArray.length; theBarrierIndex++){
if(cc.rectContainsPoint(this.aStarBarrierArray[theBarrierIndex],cc.p(ep.coordX,ep.coordY)))
{
endPointIsObstacle = true;
cc.log("你要去的位置有障碍物,请换条路线");
break;
}
}
if(!endPointIsObstacle)
this.findingPath(sp,ep);
},
findingPath:function(startPoint,endPoint){ //A*算法
var openList = []; //初始化开启列表
var closeList = []; //初始化关闭列表
startPoint.ag = 0;
startPoint.ah = 0;
startPoint.af = startPoint.ag + startPoint.ah; //起点的G,H,F值为0
openList.push(startPoint); //起点加入开启列表
var findTheWay = false;
do{
var centerNode = this.findMinNode(openList); //寻找F值最低的节点
openList.remove(centerNode); //将此节点从开启列表中删除,为了下次遍历开启列表的时候不再出现此节点
closeList.push(centerNode); //并将此节点加入到关闭列表
for(var i=0;i<8;i++) //遍历此节点周围的节点,并给这些节点加入坐标属性和G值
{
var aroundNode = {};
switch (i){
case 0:
aroundNode.coordX = centerNode.coordX+A_STAR_DISTANCE; //坐标属性
aroundNode.coordY = centerNode.coordY+A_STAR_DISTANCE;
break;
case 1:
aroundNode.coordX = centerNode.coordX+A_STAR_DISTANCE;
aroundNode.coordY = centerNode.coordY;
break;
case 2:
aroundNode.coordX = centerNode.coordX+A_STAR_DISTANCE;
aroundNode.coordY = centerNode.coordY-A_STAR_DISTANCE;
break;
case 3:
aroundNode.coordX = centerNode.coordX;
aroundNode.coordY = centerNode.coordY-A_STAR_DISTANCE;
break;
case 4:
aroundNode.coordX = centerNode.coordX-A_STAR_DISTANCE;
aroundNode.coordY = centerNode.coordY-A_STAR_DISTANCE;
break;
case 5:
aroundNode.coordX = centerNode.coordX-A_STAR_DISTANCE;
aroundNode.coordY = centerNode.coordY;
break;
case 6:
aroundNode.coordX = centerNode.coordX-A_STAR_DISTANCE;
aroundNode.coordY = centerNode.coordY+A_STAR_DISTANCE;
break;
case 7:
aroundNode.coordX = centerNode.coordX;
aroundNode.coordY = centerNode.coordY+A_STAR_DISTANCE;
break;
}
for (var barrierIndex=0; barrierIndex<this.aStarBarrierArray.length; barrierIndex++){
aroundNode.isOb = cc.rectContainsPoint(this.aStarBarrierArray[barrierIndex],cc.p(aroundNode.coordX,aroundNode.coordY)); //判断当前节点是否在障碍物形成的方框里
if(aroundNode.isOb)
break;
}
if (aroundNode.isOb){ //如果是障碍物,跳过 }
else if(closeList.hasObject(aroundNode)){ //如果在关闭列表里,跳过 }
else if(!openList.hasObject(aroundNode)){ //如果不在开启列表里,加入到开启列表
aroundNode.parentPath = centerNode;
if (Math.abs(aroundNode.coordX-endPoint.coordX)<=A_STAR_DISTANCE/2 && Math.abs(aroundNode.coordY-endPoint.coordY)<=A_STAR_DISTANCE/2) //如果节点和终点的值相近,那么A*算法结束,得到路径
{
findTheWay = true;
var pathArry = [];
this.gettingAStarPath(aroundNode,pathArry); //寻找路径
pathArry.splice(0,0,{starX:endPoint.coordX,starY:endPoint.coordY}); //加终点到数组头部
pathArry.splice(pathArry.length-1,1); //删一项数组底部的起点数据,此时的数组是最终的路径数组 this.aStarPathArray = [];
this.aStarPathArray = pathArry;
this.aStarPathArray.theIndex = this.aStarPathArray.length; this.unschedule(this.thePathSelector);
this.schedule(this.thePathSelector,null,pathArry.length-1);
break; //找到最短路径并跳出循环
}
if (aroundNode.coordX!=centerNode.coordX && aroundNode.coordY!=centerNode.coordY) //确定中心节点和周围节点形成的角度,正交G值消耗10*像素,斜角G值消耗14*像素
aroundNode.ag = centerNode.ag + A_STAR_G_EXPEND_MAX*A_STAR_DISTANCE;
else
aroundNode.ag = centerNode.ag + A_STAR_G_EXPEND_MIN*A_STAR_DISTANCE;
aroundNode.af = this.getAF(aroundNode,endPoint);
openList.push(aroundNode);
}
else if(openList.hasObject(aroundNode)){ //如果在开启列表里
var newExpend = A_STAR_G_EXPEND_MIN*A_STAR_DISTANCE;
if (aroundNode.coordX!=centerNode.coordX && aroundNode.coordY!=centerNode.coordY) //确定中心节点和周围节点形成的角度,正交G值消耗10*像素,斜角G值消耗14*像素
newExpend = A_STAR_G_EXPEND_MAX*A_STAR_DISTANCE;
if (centerNode.ag + newExpend < aroundNode.ag){ //如果新的g值小于周围节点本身的g值,那么周围节点的父节点改为当前中心节点,并重新计算其F值
aroundNode.parentPath = centerNode;
aroundNode.ag = centerNode.ag + newExpend;
aroundNode.af = this.getAF(aroundNode,endPoint);
}
}
}
}while(!findTheWay) },
findMinNode:function(openListArray){
var minNode = openListArray[0];
for (var i=0;i<openListArray.length;i++)
{
if (minNode.af>openListArray[i].af) minNode=openListArray[i];
}
return minNode;
},
getAF:function(thisNode,endNode){
var aHExpend = (Math.abs(thisNode.coordX-endNode.coordX) + Math.abs(thisNode.coordY-endNode.coordY))*A_STAR_G_EXPEND_MIN;
return aHExpend+thisNode.ag;
},
gettingAStarPath:function(laseNode,array){
if(laseNode.parentPath != null)
{
array.push({starX:laseNode.parentPath.coordX,starY:laseNode.parentPath.coordY});
this.gettingAStarPath(laseNode.parentPath,array);
}
},
thePathSelector:function(){
this.roleRunThePath(this.aStarPathArray);
},
roleRunThePath:function(array){
this.sprite.x = array[--array.theIndex].starX;
this.sprite.y = array[array.theIndex].starY;
}
}); var HelloWorldScene = cc.Scene.extend({
onEnter:function () {
this._super();
var layer = new HelloWorldLayer();
this.addChild(layer);
}
}); //这里给Array数组添加3个实例方法
Array.prototype.aStarIndexOf = function(val) { //通过对象寻找index值
for (var i = 0; i < this.length; i++) {
if (this[i].coordX==val.coordX && this[i].coordY==val.coordY) return i;
}
return -1;
};
Array.prototype.remove = function(val) { //删除相应的对象
var index = this.aStarIndexOf(val);
if (index > -1) {
this.splice(index, 1);
}
}; Array.prototype.hasObject = function(val){ //判断是否是同一个对象
for (var i = 0; i < this.length; i++){
if (this[i].coordX==val.coordX && this[i].coordY==val.coordY)
return true;
}
return false;
};
如下图,飞机在寻找路径的时候会避开红色区域。

A*寻路算法 (cocos2d-js详细代码)的更多相关文章
- Python——EM(期望极大算法)教学(附详细代码与注解)
今天,我们详细的讲一下EM算法. 前提准备 Jupyter notebook 或 Pycharm 火狐浏览器或谷歌浏览器 win7或win10电脑一台 网盘提取csv数据 需求分析 实现高斯混合模型的 ...
- cocos2d JS 使用代码判断对象类型
changeAtlasScoreString : function (score,tfScore) { if(tfScore.getDescription() == "LabelAtlas& ...
- 如何在Cocos2D游戏中实现A*寻路算法(六)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- js实现A*寻路算法
这两天在做百度前端技术学院的题目,其中有涉及到寻路相关的,于是就找来相关博客进行阅读. 看了Create Chen写的理解A*寻路算法具体过程之后,我很快就理解A*算法的原理.不得不说作者写的很好,通 ...
- 【转载】 A* 寻路算法 (个人认为最详细,最通俗易懂的一个版本)
原文地址: http://www.cppblog.com/christanxw/archive/2006/04/07/5126.html =============================== ...
- 如何在Cocos2D游戏中实现A*寻路算法(八)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 如何在Cocos2D游戏中实现A*寻路算法(一)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 6. EM算法-高斯混合模型GMM+Lasso详细代码实现
1. 前言 我们之前有介绍过4. EM算法-高斯混合模型GMM详细代码实现,在那片博文里面把GMM说涉及到的过程,可能会遇到的问题,基本讲了.今天我们升级下,主要一起解析下EM算法中GMM(搞事混合模 ...
- 4. EM算法-高斯混合模型GMM详细代码实现
1. EM算法-数学基础 2. EM算法-原理详解 3. EM算法-高斯混合模型GMM 4. EM算法-高斯混合模型GMM详细代码实现 5. EM算法-高斯混合模型GMM+Lasso 1. 前言 EM ...
- 数据挖掘领域十大经典算法之—C4.5算法(超详细附代码)
https://blog.csdn.net/fuqiuai/article/details/79456971 相关文章: 数据挖掘领域十大经典算法之—K-Means算法(超详细附代码) ...
随机推荐
- 自己动手用maven构建基于SSI的java EE应用
上篇跟大家聊了聊maven的简单使用,之前也写了一篇搭建基于SSI(struts2,spring,ibatis)的javaEE开发环境的文章,但是那篇只是给初学者搭建一个简单的SSI应用的框架,其实我 ...
- hdu1198--并查集
Problem Description Benny has a spacious farm land to irrigate. The farm land is a rectangle, and is ...
- C++malloc,calloc,realloc,free函数
在进行C/c++编程的时候,需要程序员对内存的了解比较清楚,经常需要操作的内存可分为下面几个类别: 1.堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等, ...
- HDU 1880 字符串hash 入门题
Problem Description 哈利波特在魔法学校的必修课之一就是学习魔咒.据说魔法世界有100000种不同的魔咒,哈利很难全部记住,但是为了对抗强敌,他必须在危急时刻能够调用任何一个需要的魔 ...
- Android 权限管理
从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予.此方法可以简化应用安装过程,因为用户在安装或更新应用时不需要授予权限.它还让用户可以对应 ...
- 【终极】Dynamic Web Module 3.0 requires Java 1.6 or newer
今天在用maven+ssm做项目的时候,右键项目properities设置project facet,勾选dynamic WEB module时一直勾不上,网上找了很多教程都不行, 有说在pom.xm ...
- jvm实战-基本类型占多少内存
jvm内存占用模型 对象的内存结构 对象头 Header 包含两部分数据Mark Word和Kclass: Mark Word:存储对象自身的运行时数据,如hashCode.GC分代年龄.锁状态标志. ...
- 应用Git Flow—Git团队协作最佳实践
规范的Git使用 Git是一个很好的版本管理工具,不过相比于传统的版本管理工具,学习成本比较高. 实际开发中,如果团队成员比较多,开发迭代频繁,对Git的应用比较混乱,会产生很多不必要的冲突或者代码丢 ...
- Maven3在Eclipse上安装插件
eclipse 安装插件的方式最常见的有两种: 1. 一种是在线安装,这貌似是用的最多的,就是:Help --> Install New Software,然后输入 HTTP 地址来安装,但有 ...
- jQuery 效果 - fadeTo() 方法
实例 使用淡出效果来隐藏一个 <p> 元素: $(".btn1").click(function(){ $("p").fadeTo(1000,0.4 ...