• 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 "+this._tileMap.getMapSize().width+"        height:    "+this._tileMap.getMapSize().height);
            
            // tile size: 32*32
            cc.log("tile size "+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))    
        },
    });
  • 相关阅读:
    host配置
    查看浏览器内核以及版本信息
    优化你的数据库索引
    密集索引和稀疏索引的区别
    Interview
    hadoop启动后,jps命令后发现nodename启动失败,检查日志报错:FSNamesystem initialization failed
    hadoop学习之hadoop完全分布式集群安装
    VMWare虚拟机下为Ubuntu 配置静态IP(NAT方式)ping通主机
    虚拟机突然无法使用NAT模式上网
    hadoop-0.20.2 & hbase-0.90.1 集群启动错误“org.apache.hadoop.ipc.RPC$VersionMismatch: Protocol org.apache.hadoop.hdfs.protocol.ClientP
  • 原文地址:https://www.cnblogs.com/Siegel/p/5990702.html
Copyright © 2020-2023  润新知