cocos2d-js版本A*算法
【转】http://blog.csdn.net/realcrazysun1/article/details/43054229
A*算法的东西网上讲了很多~但还是不可避免的要去研究一下,cocos官网上有一个cocos2dx版本的A星算法(cocos2d-x A星算法),正好拿来改造一下,顺便踩踩cocos2d-js的坑
原理和伪代码部分可以参考这个(A*算法伪代码)废话不多说,直接上正题.
主要有2个封装原型类:
1、GameLayer:负责加载地图、保持地图跟随、坐标转换、地图上物品判断、接受触控事件
var GameLayer = cc.Layer.extend({
_tileMap:null,
_bgLayer:null,
_objectLayer:null,
_batchNode:null,
_cat:null,
bonesCount:null,
ctor:function () {
// ////////////////////////////
// 1. super init first
this._super();
// 加载地图
this._tileMap = new cc.TMXTiledMap(res.CatMaze_tmx);
this._bgLayer = this._tileMap.getLayer("Background");
this._objectLayer = this._tileMap.getLayer("Objects");
this.addChild(this._tileMap); // 25*25 tiles
cc.log("map size width:"+this._tileMap.getMapSize().width+" height: "+this._tileMap.getMapSize().height); // tile size: 32*32
cc.log("tile size width:"+this._tileMap.getTileSize().width+" height: "+this._tileMap.getTileSize().height); // tile坐标
var spawnTileCoord = cc.p(24, 0);
var spawnPos = this.positionForTileCoord(spawnTileCoord); // 视角跟随
this.setViewpointCenter(spawnPos);
// 背景音乐
cc.audioEngine.playMusic(res.SuddenDefeat_mp3,true); cc.spriteFrameCache.addSpriteFrames(res.CatMaze_plist); //存放在地图上面~则会跟随地图
this._batchNode = new cc.SpriteBatchNode(res.CatMaze_png);
this._tileMap.addChild(this._batchNode); this._cat = new CatSprite(this);
this._cat.setPosition(spawnPos);
this._batchNode.addChild(this._cat); // bmfont 字体
this.bonesCount = new cc.LabelBMFont("Bones: 0", res.Arial_fnt);
this.bonesCount.setPosition(400, 30);
this.addChild(this.bonesCount); cc.eventManager.addListener({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: true,
onTouchBegan:function (touch, event) {
// 猫移动向该点
var point = event.getCurrentTarget()._tileMap.convertTouchToNodeSpace(touch);
cc.log("touch point x: "+point.x+"y: "+point.y);
event.getCurrentTarget()._cat.moveToward(point);
return true;
}
}, this); this.scheduleUpdate();
return true;
}, // 坐标转换为tile
positionForTileCoord:function(p){
var x = (p.x * this._tileMap.getTileSize().width) + this._tileMap.getTileSize().width / 2;
var y = (this._tileMap.getMapSize().height *this. _tileMap.getTileSize().height) -
(p.y *this._tileMap.getTileSize().height) - this._tileMap.getTileSize().height / 2;
return cc.p(x, y);
}, // 地图跟随
setViewpointCenter:function(position){
var size = cc.director.getWinSize();
var x = Math.max(position.x, size.width / 2);
var y = Math.max(position.y, size.height / 2);
x = Math.min(x, (this._tileMap.getMapSize().width * this._tileMap.getTileSize().width) - size.width / 2);
y = Math.min(y, (this._tileMap.getMapSize().height * this._tileMap.getTileSize().height) - size.height / 2);
var p = cc.p(x,y);
var center = cc.p(size.width/2,size.height/2);
var viewPoint = cc.pSub(center,p); this._tileMap.setPosition(viewPoint);
},
update:function(){
this.setViewpointCenter(this._cat.getPosition());
},
tileCoordForPosition:function(position){
var x = parseInt( position.x / this._tileMap.getTileSize().width);
var y = parseInt(((this._tileMap.getMapSize().height *this._tileMap.getTileSize().height) - position.y) / this._tileMap.getTileSize().height);
return cc.p(x, y);
},
//是否是墙壁
isWallAtTileCoord:function(tileCoord){
return this.isPropAtTileCoordForLayer("Wall", tileCoord, this._bgLayer);
},
//显示骨头
showNumBones:function(numBones)
{
this.bonesCount.setString("Bones: "+ numBones);
},
isValidTileCoord:function(tileCoord){
if (tileCoord.x < 0 || tileCoord.y < 0 ||
tileCoord.x >= this._tileMap.getMapSize().width ||
tileCoord.y >= this._tileMap.getMapSize().height)
{
return false;
}
else
{
return true;
}
},
//是否有骨头
isBoneAtTilecoord:function(tileCoord)
{
//bone 存放在_objectLayer上
return this.isPropAtTileCoordForLayer("Bone", tileCoord, this._objectLayer);
},
//是否有狗
isDogAtTilecoord:function(tileCoord)
{
return this.isPropAtTileCoordForLayer("Dog", tileCoord, this._objectLayer);
}, //是否为出口
isExitAtTilecoord:function(tileCoord)
{
return this.isPropAtTileCoordForLayer("Exit", tileCoord, this._objectLayer);
}, //判断tile上存放了什么
isPropAtTileCoordForLayer:function(prop,tileCoord, layer)
{
if (!this.isValidTileCoord(tileCoord))
{
return false;
} //获得tile对应id
var gid = layer.getTileGIDAt(tileCoord); //这里返回的是dict类型
var properties = this._tileMap.getPropertiesForGID(gid);
if (properties==null)
{
return false;
}
return properties[prop]==1;
},
//移除tiles
removeObjectAtTileCoord:function(tileCoord){
this._objectLayer.removeTileAt(tileCoord);
},
winGame:function(){
cc.log("win");
this.endScene();
},
loseGame:function(){
cc.log("lose");
this.endScene();
},
endScene:function()
{
var self = this;
this._cat.runAction(cc.sequence( cc.scaleBy(0.5, 3.0),
cc.delayTime(1.0),
cc.scaleTo(0.5, 0.0),
cc.callFunc(self.showRestartMenu, self)
));
this._cat.runAction(cc.repeatForever(cc.rotateBy(0.5, 360.0)));
},
showRestartMenu:function(){
cc.log("showRestartMenu");
},
//是否可以通过
walkableAdjacentTilesCoordForTileCoord:function(tileCoord){
var tmp = [];
// 上
var p1=cc.p(tileCoord.x, tileCoord.y - 1);
if (this.isValidTileCoord(p1) && !this.isWallAtTileCoord(p1)){
tmp.push(p1);
}
// 左
var p2=cc.p(tileCoord.x - 1, tileCoord.y);
if (this.isValidTileCoord(p2) && !this.isWallAtTileCoord(p2)){
tmp.push(p2);
}
// 下
var p3=cc.p(tileCoord.x, tileCoord.y + 1);
if (this.isValidTileCoord(p3) && !this.isWallAtTileCoord(p3)){
tmp.push(p3);
}
// 右
var p4=cc.p(tileCoord.x + 1, tileCoord.y);
if (this.isValidTileCoord(p4) && !this.isWallAtTileCoord(p4)){
tmp.push(p4);
}
cc.log("tileCoord: "+tileCoord.x+" "+tileCoord.y);
for(var i = 0;i<tmp.length;i++){
cc.log("tmp "+i+": "+tmp[i].x+ " "+tmp[i].y);
}
return tmp;
}
});
2、CatSprite:负责A*算法实现、猫展示动画
var CatSprite = cc.Sprite.extend({
_gameLayer:null,
_facingForwardAnimation:null,
_facingBackAnimation:null,
_facingLeftAnimation:null,
_facingRightAnimation:null,
_bonenum:0,
_shortestPath:[],//最短路径
_spOpenSteps:[],//开放列表
_spClosedSteps:[],//关闭列表
_tempShortestPath:[],
ctor:function(gameLayer){
this._super("#cat_forward_1.png");
this._gameLayer = gameLayer; this._facingForwardAnimation = this.createCatAnimation("forward"); this._facingBackAnimation = this.createCatAnimation("back"); this._facingLeftAnimation = this.createCatAnimation("left"); this._facingRightAnimation = this.createCatAnimation("right"); return true;
}, moveToward:function(target){
cc.log("moveToward");
var fromTileCoord = this._gameLayer.tileCoordForPosition(this.getPosition());
var toTileCoord = this._gameLayer.tileCoordForPosition(target); if(toTileCoord.x == fromTileCoord.x&&toTileCoord.y==fromTileCoord.y){
cc.log("You're already there! :P");
return;
}
if(!this._gameLayer.isValidTileCoord(toTileCoord) ||this._gameLayer.isWallAtTileCoord(toTileCoord)){
cc.audioEngine.playEffect(res.hitWall_wav);
return;
}
cc.log("From: " + fromTileCoord.x + " "+ fromTileCoord.y);
cc.log("To: " + toTileCoord.x + " "+ toTileCoord.y); this._spOpenSteps = [];
this._spClosedSteps = [];
// 首先,添加猫的方块坐标到open列表
this.insertInOpenSteps(new ShortestPathStep(fromTileCoord));
do{
//这里要当心死循环
var currentStep = this._spOpenSteps[0];
currentStep.retain();
cc.log("currentStep:"+currentStep.getPosition().x+" "+currentStep.getPosition().y);
// 添加当前步骤到closed列表
this._spClosedSteps.push(currentStep);
// 将它从open列表里面移除
this._spOpenSteps.splice(0,1);
// 如果当前步骤是目标方块坐标,那么就完成了
if (toTileCoord.x == currentStep.x&&toTileCoord.y==currentStep.y){
cc.log("path found");
this.constructPathAndStartAnimationFromStep(currentStep);
this._spOpenSteps = [];
this._spClosedSteps = [];
break;
}
//this.printPath(currentStep);
var adjSteps = this._gameLayer.walkableAdjacentTilesCoordForTileCoord(currentStep.getPosition());
for (var i = 0; i < adjSteps.length; ++i){
var step = new ShortestPathStep(adjSteps[i]);
if (this.indexOf(this._spClosedSteps,step)!=-1){ continue;
}
var moveCost = this.costToMoveFromStepToAdjacentStep(currentStep, step);
var index = this.indexOf(this._spOpenSteps,step);
if (index == -1){
step.setParent(currentStep);
step.setGScore(currentStep.getGScore() + moveCost);
step.setHScore(this.computeHScoreFromCoordToCoord(step.getPosition(), toTileCoord));
this.insertInOpenSteps(step);
}else{
step = this._spOpenSteps[index];
if ((currentStep.getGScore() + moveCost) < step.getGScore()){
step.setGScore(currentStep.getGScore() + moveCost);
// 因为G值改变了,F值也会跟着改变
// 所以为了保持open列表有序,需要将此步骤移除,再重新按序插入
// 在移除之前,需要先保持引用
// step.retain();
// 现在可以放心移除,不用担心被释放
this._spOpenSteps.splice(index,1);
// // 重新按序插入
this.insertInOpenSteps(step);
// // 现在可以释放它了,因为open列表应该持有它
// step.release();
}
}
}
}while (this._spOpenSteps.length > 0); for (var i = 0;i<this._shortestPath.length;i++){
cc.log("Description:", this._shortestPath[i].getDescription());
} }, //序列帧动画
createCatAnimation:function(animType)
{
var animation = new cc.Animation();
for (var i = 1; i <= 2; ++i)
{
animation.addSpriteFrame(cc.spriteFrameCache.getSpriteFrame("cat_"+animType+"_"+i+".png"));
}
animation.setDelayPerUnit(0.2);
animation.retain()
return animation;
}, //用来判断step所在位置
indexOf:function(array,step){
if(array.length>0){
for(var i = 0;i<array.length;i++){
if(array[i].isEqual(step)){
return i;
}
}
}
return -1;
}, //插入一个step 维护一个有序列表
insertInOpenSteps:function(step)
{
var stepFScore = step.getFScore();
var count = this._spOpenSteps.length;
var i ;
for (i = 0; i < count; ++i)
{
if (stepFScore <= this._spOpenSteps[i].getFScore())
{
break;
}
} this._spOpenSteps.splice(i, 0, step);
}, //计算H值
computeHScoreFromCoordToCoord:function(fromCoord,toCoord)
{
// 这里使用曼哈顿方法,计算从当前步骤到达目标步骤,在水平和垂直方向总的步数
// 忽略了可能在路上的各种障碍
return Math.abs(toCoord.x - fromCoord.x) + Math.abs(toCoord.y - fromCoord.y);
},
//这里可以扩展~
costToMoveFromStepToAdjacentStep:function(fromStep,toStep){
//return ((fromStep->getPosition().x != toStep->getPosition().x)
// && (fromStep->getPosition().y != toStep->getPosition().y)) ? 14 : 10;
return 1;
}, //构造最短路径
constructPathAndStartAnimationFromStep:function(step){
this._shortestPath=[];
do{
// 起始位置不要进行添加
if (step.getParent())
{
// 总是插入到索引0的位置,以便反转路径
this._shortestPath.splice(0,0,step);
}
step = step.getParent(); // 倒退
} while (step); // 直到没有上一步
for (var i = 0;i<this._shortestPath.length;i++){
cc.log("Description:", this._shortestPath[i].getDescription());
}
this.popStepAndAnimate();
},
//打印路径
printPath:function(step){
this._tempShortestPath=[];
do{
// 起始位置不要进行添加
if (step.getParent())
{
// 总是插入到索引0的位置,以便反转路径
this._tempShortestPath.splice(0,0,step);
}
step = step.getParent(); // 倒退
} while (step); // 直到没有上一步
for (var i = 0;i<this._tempShortestPath.length;i++){
cc.log("Description:", this._tempShortestPath[i].getDescription());
}
cc.log("---------------------------------------------------------------------");
},
//展示运动
popStepAndAnimate:function(){
var currentPosition = this._gameLayer.tileCoordForPosition(this.getPosition());
if(this._gameLayer.isBoneAtTilecoord(currentPosition)){
this._bonenum++;
this._gameLayer.showNumBones(this._bonenum);
this._gameLayer.removeObjectAtTileCoord(currentPosition);
}else if(this._gameLayer.isDogAtTilecoord(currentPosition)){
if (this._bonenum <= 0){
this._gameLayer.loseGame();
return;
}else{
this._bonenum--;
this._gameLayer.showNumBones(this._bonenum);
this._gameLayer.removeObjectAtTileCoord(currentPosition);
}
}else if (this._gameLayer.isExitAtTilecoord(currentPosition)){
this._gameLayer.winGame();
} var s = this._shortestPath[0]; if(s==undefined){
return;
}
s.retain();
var futurePosition = s.getPosition(); var diff = cc.pSub(futurePosition , currentPosition);
if (Math.abs(diff.x) > Math.abs(diff.y)){
if (diff.x > 0){
this.runAction(cc.animate(this._facingRightAnimation));
}else{
this.runAction(cc.animate(this._facingLeftAnimation));
}
}else{
if (diff.y > 0){
this.runAction(cc.animate(this._facingForwardAnimation));
}else{
this.runAction(cc.animate(this._facingBackAnimation));
}
} var moveAction = cc.moveTo(0.4, this._gameLayer.positionForTileCoord(s.getPosition())); this._shortestPath[0].retain();
this._shortestPath.splice(0,1);
var moveCallback = cc.callFunc(this.popStepAndAnimate,this);
this.runAction(cc.sequence(moveAction,moveCallback))
},
});
cocos2d-js版本A*算法的更多相关文章
- JS中常见算法问题
JS中常见算法问题 1. 阐述JS中的变量提升(声明提前) 答:将所有的变量提升当当前作用域的顶部,赋值留在原地.意味着我们可以在某个变量声明前就使用该变量. 虽然JS会进行变量提升,但并不会执行真正 ...
- RSA 加密 解密 (长字符串) JAVA JS版本加解密
系统与系统的数据交互中,有些敏感数据是不能直接明文传输的,所以在发送数据之前要进行加密,在接收到数据时进行解密处理:然而由于系统与系统之间的开发语言不同. 本次需求是生成二维码是通过java生成,由p ...
- AES加密 Pkcs7 (BCB模式) java后端版本与JS版本对接
1.BCB模式是需要设置iv偏移量和Key值,这两个值就像账号和密码一样,当这两个值一致时才能确保加密和解密的数据一致.(ps:这两个值千万不能暴露出去哦!) 2.JAVA版本代码: 这里的iv偏移量 ...
- Atitit js版本es5 es6新特性
Atitit js版本es5 es6新特性 Es5( es5 其实就是adobe action script的标准化)1 es6新特性1 Es5( es5 其实就是adobe action scrip ...
- [Effective JavaScript笔记]第1条:了解使用的js版本
1997年 正式成为国际标准,官方名称为ECMAScript. 1999年 定稿第3版ECMAScript标准(简称ES3),最广泛的js版本. 2009年 发布第5版即ES5,引入了一些新特性,标准 ...
- JS版本网站资源状态检测
Title:JS版本网站资源状态检测 --2012-08-28 14:08 前几天需要一个网站状态检测的东东,后面写了个蹩脚的JS版本,里面用到了以前没用过的东西,在这里记下来,其实批处理加curl ...
- js实现的文章输入检查与测速。(纯js版本)
朋友又提出一些需求.希望不要jquery .于是修改成js版本. <!DOCTYPE html> <html> <head> <meta charset=&q ...
- diff.js 列表对比算法 源码分析
diff.js列表对比算法 源码分析 npm上的代码可以查看 (https://www.npmjs.com/package/list-diff2) 源码如下: /** * * @param {Arra ...
- Mac下nvm管理node.js版本问题
本篇文章主要是针对已经安装了node.js和nvm管理工具小伙伴遇到的问题. 管理工具有两个,一个是nvm,还有一个是nnvm的好处就是可以管理多个node版本,而且可以切换想要的版本,可以安装一个稳 ...
- 限定项目的 Node.js 版本
限定项目运行所需的 Node.js 版本可保证项目在一个稳定可预期的环境中运行,减少不必要的故障.甚至有些依赖库只能工作于某些版本下.同时,不加以限制的话,在多人合作的项目中恐怕会引起环境不一致带来的 ...
随机推荐
- ubuntu14 + nginx + php
ubuntu14 1.安装nginx sudo apt-get install nginx 安装之后的文件结构大致为: * 所有的配置文件都在/etc/nginx下,并且每个虚拟主机已经安排在了/et ...
- java类型转化之SimpleDateFormat-时间转化
关于Date,时间戳(long),String类型之间的相互转换,主要是用到类SimpleDateFormat. 先介绍SimpleDateFormat类的一些常见格式: 1.参数: code des ...
- python数据结构与算法——图的基本实现及迭代器
本文参考自<复杂性思考>一书的第二章,并给出这一章节里我的习题解答. (这书不到120页纸,要卖50块!!,一开始以为很厚的样子,拿回来一看,尼玛.....代码很少,给点提示,然后让读者自 ...
- Python变量、数据类型6
1.Python变量 变量,即代表某个value的名字. 变量的值存储在内存中,这意味着在创建变量时会在内存中开辟一个空间. !!!即值并没有保存在变量中,它们保存在计算机内存的深处,被变量引用.所以 ...
- Spring将多个配置文件引入一个配置文件中
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- webpack 代码拆分,按需加载
转自:https://segmentfault.com/a/1190000007649417?utm_source=weekly&utm_medium=email&utm_campai ...
- Ubuntu Gnome16.04下安装cuda、theano和opencv
1. 安装显卡驱动 ~$ lspci | grep controller00:02.0 VGA compatible controller: Intel Corporation Sky Lake In ...
- 黄聪:wordpress向一个页面POST数据,出现404页面访问不了
出现这个情况,说明POST的数据中存在一些关键词,触发调用了page以外的模版.比如POST数据中有 name , author 等参数. 解决办法,就是把这些参数改一下名称.
- [IIS]IIS扫盲(七)
(4)汉化补丁 许多软件都是英文版本的,国人的英语水平普遍不高,包括笔者.因为这个,影响了不少人学习电脑的兴趣. 为了占领市场,软件开发商提供了中文版本:为了大家学习方便,爱好汉化工作的国人制作了汉化 ...
- 利用反射及JDBC元数据编写通用查询方法
元数据:描述数据的数据,ResultSetMetaData是描述ResultSet的元数据对象,从它可以得到数据集有多少了,每一列的列名... ResultSetMetaData可以通过ResultS ...