cocos2d-js版本A*算法
来源:互联网 发布:黄海波惹了谁 知乎 编辑:程序博客网 时间:2024/05/17 03:37
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))},});
源码地址
0 0
- cocos2d-js版本A*算法
- cocos2d - JS A*算法
- A*算法JS版本
- cocos2d js 调用 c++ 版本cocos2d js 3.6
- Cocos2d-JS 3.12版本Windows环境配置
- JS-A*算法
- JS a*算法
- A*算法 带cocos2d-x例子 a*寻路算法
- 如何使用Cocos2D实现A星寻路算法
- cocos2d-x之简易A*算法
- 【cocos2D-x学习】16.A*算法
- 【cocos2D-x学习】16.A*算法
- 【cocos2D-x学习】16.A*算法
- 使用cocos2d js接入有米广告-ios版本
- 开发cocos2d-js项目总结(js3.6版本)
- cocos2d js接入有米广告-ios版本
- cocos2d-js v3.10 版本高级混淆 socketio 踩坑
- A*智能寻路算法(php版本)
- 在windows环境下从wordpress迁移到jekyll
- 渐变时间点计算
- 二叉树实现
- 垃圾申通快递
- 九度1014(排序)
- cocos2d-js版本A*算法
- 线性表
- hdu1004——Let the Balloon Rise
- 嵌入式stm32学习之路——第一弹(led流水灯工程)
- HTML使用Angular JS加载银行信息遍历成Radio
- org.hibernate.StaleStateException: Unexpected row count: 0 expected: 1
- delete指针以后应赋值为NULL
- 虚拟主机Web应用开发时应该注意到的安全问题
- 什么才是程序员的核心竞争力?