cocos2d-js版本A*算法

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,//是否是墙壁
    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",this._objectLayer);
    },//是否有狗
    isDogAtTilecoord:function(tileCoord) 
    {
    	return this.isPropAtTileCoordForLayer("Dog",//是否为出口
    isExitAtTilecoord:function(tileCoord) 
    {
    	return this.isPropAtTileCoordForLayer("Exit",//判断tile上存放了什么
    isPropAtTileCoordForLayer:function(prop,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,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,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,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))	
	},});

源码地址

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是