【Cocos Creator实战教程(6)】——get47(数字消除)

先来看一下游戏效果

电脑端:http://www.potato47.cn/get47
手机端:http://www.potato47.cn/get47-m
微信扫描:
这里写图片描述

游戏玩法:
这里写图片描述

  • 游戏操作仿的是天天爱消除,点击一个方块向相邻的方块滑动就会交换两个方块
  • 当没有可移动的方块时,可以点击下面的update按钮
  • 横向相连的方块数字之和会增加分数,纵向相连的方块数字之和会减少分数
  • 最终目的就是get47

为什么是47呢?

因为47是我们的女主角嘛


这是我们的游戏场景
这里写图片描述

Tile就代表方块,TileLayout就是用来装Tile的,当然我们还是会在脚本里动态添加tile,整体结构很简单,根据工程文件就可以看的很清楚,这里就不讲了

下面来重点讲一下算法

先来看一下Tile的脚本
Tile.js

cc.Class({
    extends: cc.Component,

    properties: {
        pics:{
            type:cc.SpriteFrame,
            default:[],
        },
        _type:1,
        posIndex:cc.Vec,
        type:{
            set:function(value){
                this._type = value;
                this.node.getComponent(cc.Sprite).spriteFrame = this.pics[value-1];
            },
            get:function(){
                return this._type;  
            }
        },
        isAlive:true
    },

    onLoad: function () {
        this.initType();
    },

    initType:function(){
        this.type = Math.floor(Math.random()*this.pics.length) + 1 ;
    },
});

这里有三个重要的属性,type,isAlive,posIndex,先记住它们

再来看一下TileController的脚本的主要方法

这里写图片描述

这几个方法里最核心的就是中间的三个:deleteTiles,fallTiles,addTiles
顾名思义,
deleTiles:删除相连接的方块
fallTiles:deleTiles后会有一些空白,这时就需要把上面的方块落下来
addTiles:fallTiles后上面就有一些空白,所以就要在上面填上新的方块

他们的伦理关系如下(如果你们觉得我的字好看,请夸我一下,如果觉得不好看,请保持沉默。。。)
这里写图片描述
由于大小限制,图片有点渣。。。

Tile里有一个posIndex,这个属性是用来标记tile的位置信息的,之所以要用一个属性来标记,而不是直接移动位置,是为了实现tile的动画效果,因为在fallTiles时,会有很多的tile同时落下,我们的做法是先把所有要下落的tile找出来,然后一起让他们执行动作:position=posIndex

主体思路如上,具体的细节请看代码
TileController.js

var DIR = cc.Enum({
    UP:-1,
    DOWN:-1,
    LEFT:-1,
    RIGHT:-1
});
var GAME_STATE = cc.Enum({
    PLAYING:-1,
    WIN:-1
});
cc.Class({
    extends: cc.Component,

    properties: {
        gameState:{
            type:GAME_STATE,
            default:GAME_STATE.PLAYING
        },
        score:0,
        scoreLabel:cc.Label,
        tiles:[],
        tilesLayout:cc.Node,
        tilePrefab:cc.Prefab,
        rowNum:0,
        colNum:0,
        padding:0,
        spacing:0,
    },

    init: function (game) {
        this.game = game;
        this.scoreLabel.string = this.score+"";
        this.gameState = GAME_STATE.PLAYING;
        this.tileWidth = (this.tilesLayout.width - this.padding*2 - this.spacing*(this.colNum-1))/this.colNum;
        for(let y=0;y<this.rowNum;y++){
            for(let x=0;x<this.colNum;x++){
                let tile = cc.instantiate(this.tilePrefab);
                this.tilesLayout.addChild(tile);                
                tile.width = this.tileWidth;
                tile.height = this.tileWidth;
                tile.position = cc.p(this.padding + x*(this.tileWidth+this.spacing),
                    this.padding + y*(this.tileWidth+this.spacing));
                tile.getComponent("Tile").posIndex = tile.position;
                tile.tag = y*this.colNum + x;
                this.addTouchEvent(tile);
                this.tiles.push(tile);
            }
        }
        this.touchAble = false;
        this.deleteTiles();
    },

    addTouchEvent(tile){
        var p1,p2,dir;
        let self = this;
        var getDir = function(){
            if(Math.abs(p2.x-p1.x) > Math.abs(p2.y-p1.y)){
                if(p2.x>p1.x){
                    dir = DIR.RIGHT;
                }else{
                    dir = DIR.LEFT;
                }
            }else{
                if(p2.y>p1.y){
                    dir = DIR.UP;
                }else{
                    dir = DIR.DOWN;
                }
            }
            if(self.gameState === GAME_STATE.PLAYING && self.touchAble){
                self.touchAble = false;
                self.tryExchange(tile, dir);
            }
        }
        tile.on('touchstart',function(e){
            p1 = e.getLocation();
        },this);
        tile.on('touchmove',function(e){

        },this);
        tile.on('touchend',function(e){
            p2 = e.getLocation();
            getDir();
        },this);
        tile.on('touchcancel',function(e){
            p2 = e.getLocation();
            getDir();
        },this);

    },

    tryExchange(tile,dir){
        var neighborTile = this.getNeighborTile(tile,dir);
        if(neighborTile === null){
            return;
        }

        this.exchangeTwoTilesState(tile, neighborTile);
        var hLines = this.getHorizontalLines();
        var vLines = this.getVerticalLines();
        if(hLines.length+vLines.length > 0){
            this.exchangeTwoTilesPosIndex(tile, neighborTile);
            let finished = 0;
            let total = 2;
            let self = this;
            let action1 = cc.sequence(cc.moveTo(0.15,tile.getComponent("Tile").posIndex),
                cc.callFunc(function(){
                    finished++;
                    if(finished == total){
                        self.deleteTiles();
                    }
                })
            );
            let action2 = cc.sequence(cc.moveTo(0.15,neighborTile.getComponent("Tile").posIndex),
                cc.callFunc(function(){
                    finished++;
                    if(finished == total){
                        self.deleteTiles();
                    }
                })
            );
            tile.runAction(action1);
            neighborTile.runAction(action2);
        }else{
            this.exchangeTwoTilesState(tile, neighborTile);
            var finished = 0;
            var total = 2;
            var self = this;
            var tilePos = tile.position;
            var neighborTilePos = neighborTile.position;
            var action1 = cc.sequence(cc.moveTo(0.1,neighborTilePos),cc.moveTo(0.1,tilePos),
                cc.callFunc(function(){
                    finished++;
                    if(finished == total){
                        self.touchAble = true;
                    }
                })
            );
            var action2 = cc.sequence(cc.moveTo(0.1,tilePos),cc.moveTo(0.1,neighborTilePos),
                cc.callFunc(function(){
                    finished++;
                    if(finished == total){
                        self.touchAble = true;
                    }
                })
            );
            tile.runAction(action1);
            neighborTile.runAction(action2);
        }


    },

    exchangeTwoTilesState(tile1,tile2){
        this.tiles[tile1.tag] = tile2;
        this.tiles[tile2.tag] = tile1;

        var tile1Tag = tile1.tag;
        tile1.tag = tile2.tag;
        tile2.tag = tile1Tag;
    },

    exchangeTwoTilesPosIndex(tile1,tile2){//交换位置信息,实际位置没有改变
        var tile1Pos = tile1.getComponent("Tile").posIndex;
        var tile2Pos = tile2.getComponent("Tile").posIndex;

        tile1.getComponent("Tile").posIndex = tile2Pos;
        tile2.getComponent("Tile").posIndex = tile1Pos;
    },

    deleteTiles(){
        let self = this;
        var hLines = this.getHorizontalLines();
        var vLines = this.getVerticalLines();
        if(hLines.length + vLines.length===0){
            this.touchAble = true;
            return;
        }
        var addNumber = 0;//横加竖减
        var minusNumber = 0;
        var lines = [];
        for(let i in hLines){
            addNumber += hLines[i].getComponent("Tile").type;
            lines.push(hLines[i]);
        }
        for(let i in vLines){
            minusNumber += vLines[i].getComponent("Tile").type;
            let isExist = false;
            for(let j in hLines){
                if(hLines[j] === vLines[i]){
                    isExist = true;
                }
            }
            if(!isExist){
                lines.push(vLines[i]);
            }
        }

        this.score += (addNumber - minusNumber);
        if(this.score === 47){
            this.gameState = GAME_STATE.WIN;
            this.scoreLabel.string = "YOU GET 47!";
        }else{
            this.scoreLabel.string = this.score+"";
        }

        var finished = 0;
        var total = lines.length;
        for(let i=0;i<total;i++){
            let action = cc.sequence(cc.scaleTo(0.15, 0, 0),
                cc.callFunc(function(){
                    finished++;
                    if(finished == total){
                        self.fallTiles();
                    }
                })
            );
            lines[i].getComponent("Tile").isAlive = false;
            lines[i].runAction(action);
        }
    },

    fallTiles(){
        let self = this;
        //下落
        var isAllFall = false;
        while(!isAllFall){
            isAllFall = true;
            for(let y=1;y<this.rowNum;y++){
                for(let x=0;x<this.rowNum;x++){
                    if(this.tiles[y*this.colNum+x].getComponent("Tile").isAlive && !this.tiles[(y-1)*this.colNum+x].getComponent("Tile").isAlive){
                        this.exchangeTwoTilesState(this.tiles[y*this.colNum+x], this.tiles[(y-1)*this.colNum+x]);
                        this.exchangeTwoTilesPosIndex(this.tiles[y*this.colNum+x], this.tiles[(y-1)*this.colNum+x]);
                        isAllFall = false;
                    }
                }
            }
        }
        var fallingTiles = [];
        for(let i in this.tiles){
            if(this.tiles[i].getComponent("Tile").posIndex !== this.tiles[i].position){
                fallingTiles.push(this.tiles[i]);
            }
        }

        var finished = 0;
        var total = fallingTiles.length;
        for(let i=0;i<total;i++){
            let action = cc.sequence(cc.moveTo(0.3, fallingTiles[i].getComponent("Tile").posIndex),
                cc.callFunc(function(){
                    finished++;
                    if(finished == total){
                        self.addTiles();
                    }
                })
            );
            fallingTiles[i].runAction(action);
        }

    },

    addTiles(){
        let self = this;
        //填补空白
        var addingTiles = [];
        for(let y=0;y<this.rowNum;y++){
            for(let x=0;x<this.rowNum;x++){
                if(!this.tiles[y*this.colNum+x].getComponent("Tile").isAlive){
                    addingTiles.push(this.tiles[y*this.colNum+x]);
                }
            }
        }

        var finished = 0;
        var total = addingTiles.length;
        for(let i=0;i<total;i++){
            let action = cc.sequence(cc.scaleTo(0.15, 1,1),
                cc.callFunc(function(){
                    finished++;
                    if(finished == total){
                        self.deleteTiles();
                    }
                })
            );
            addingTiles[i].getComponent("Tile").initType();
            addingTiles[i].getComponent("Tile").isAlive = true;
            addingTiles[i].runAction(action);
        }
    },

    getVerticalLines(){
        var lineTiles = [];
        var count = 1;
        for(let x=0;x<this.colNum;x++){
            for(let y=0;y<this.rowNum-2;y=y+count){
                let tile = this.tiles[y*this.colNum+x];
                let tileType = tile.getComponent("Tile").type;
                count = 1;
                for(let n=y+1;n<this.rowNum;n++){
                    if(this.tiles[n*this.colNum+x].getComponent("Tile").type === tileType){
                        count++;
                    }else{
                        break;
                    }
                }
                if(count>=3){
                    for(let i=0;i<count;i++){
                        lineTiles.push(this.tiles[(y+i)*this.colNum+x]);
                    }
                }
            }
        }
        return lineTiles;
    },

    getHorizontalLines(){
        var lineTiles = [];
        var count = 1;
        for(let y=0;y<this.rowNum;y++){
            for(let x=0;x<this.colNum-2;x=x+count){
                let tile = this.tiles[y*this.colNum+x];
                let tileType = tile.getComponent("Tile").type;
                count = 1;
                for(let n=x+1;n<this.colNum;n++){
                    if(this.tiles[y*this.colNum+n].getComponent("Tile").type === tileType){
                        count++;
                    }else{
                        break;
                    }
                }
                if(count>=3){
                    for(let i=0;i<count;i++){
                        lineTiles.push(this.tiles[y*this.colNum+x+i]);
                    }
                }
            }
        }
        return lineTiles;
    },

    getNeighborTile(tile,dir){
        var x = tile.tag % this.colNum;
        var y = (tile.tag-x) / this.rowNum;
        switch(dir){
            case DIR.LEFT:
                if(x===0){
                    return null
                }else{
                    return this.tiles[y*this.colNum+(x-1)];
                }
            case DIR.RIGHT:
                if(x===this.colNum-1){
                    return null
                }else{
                    return this.tiles[y*this.colNum+(x+1)];
                }
            case DIR.UP:
                if(y===this.rowNum-1){
                    return null
                }else{
                    return this.tiles[(y+1)*this.colNum+x];
                }
            case DIR.DOWN:
                if(y===0){
                    return null
                }else{
                    return this.tiles[(y-1)*this.colNum+x];
                }
        }
    },

    newView(){
        if(this.gameState == GAME_STATE.PLAYING && this.touchAble == true){
            var self = this;
            this.touchAble = false;
            var finished = 0;
            var total = this.tiles.length;
            for(let i=0;i<total;i++){
                let action = cc.sequence(cc.scaleTo(0.3, 0, 0),
                    cc.callFunc(function(){
                        finished++;
                        if(finished == total){
                            self.addTiles();
                        }
                    })
                );
                this.tiles[i].getComponent("Tile").isAlive = false;
                this.tiles[i].runAction(action);
            }
        }
    }
});

工程文件:

https://github.com/potato47/get47

后话:

成功得到分数47,会显示”You get 47!”,但是我的直觉告诉我,好像时态不对,原谅很渣的英语水平。。。


这里写图片描述

所以,就有了这个游戏

所以,想看什么方面的教程可以再博客下面或者微信公众号里留言

所以,你还不关注一下公众号?

新手程序员:xinshouit
这里写图片描述

新做的游戏可以在公众号里在线玩,博客更新也会在里面提醒

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值