游戏开发之旅——使用CocosCreator完成卡牌2048主要逻辑

周末在家玩别人的小游戏时发现一个比较有意思的休闲游戏,这里实现其中主要的逻辑,代码基本注释都有,比较清晰

效果如下:
请添加图片描述

  • 1:生成5个竖着的区域来放牌
    -在本例中我使用了一个预制体资源来动态生成5个放置区域
    在这里插入图片描述
    //代码如下
//生成放置区域
    drawBlocks() {
        //算出每个区域的size。主要为width,height固定了
        this.blockSize = (cc.winSize.width - this.gap * (ROWS + 1)) / ROWS;
        let x = this.gap + this.blockSize/2;//第一个放置区域位置
        for (let i = 0; i < ROWS; ++i) {//动态生成放置的区域,
            let node = {};
            let block = cc.instantiate(this.blockPre);//动态生成预制体
            block.width = this.blockSize;
            block.height = this.pokeNode.height;
            this.pokeNode.addChild(block);
            block.setPosition(cc.v2(x, block.height/2));
            node.item = block;//保存一波节点信息
            node.fill = new Array();
            this.block.push(node);
            x += this.gap+ this.blockSize;//增加区域的x坐标
            
            // cc.log(block.getPosition());
        }
    },
  • 2:卡牌的生成
    -在卡牌生成中,我本地使用了一个create_left()和一个create_right()方法(不提倡),建议封装一个方法使用。每次拖动了正确的到放置区域后要将left的转移到right去,然后再生成一个在left的位置。这里我只贴一个生成的信息
    //代码如下
    //生成一个牌
    createLeft:function(){
        let poke = {};
        var a = Math.floor(Math.random() * 3);//随机生成//不建议如此操作,建议生成后按照数字选取sprite资源
        if (a == 0) { this.pokePrefab = this.card_blue }
        if (a == 1) { this.pokePrefab = this.card_green }
        if (a == 2) { this.pokePrefab = this.card_red }
        var poke_left = cc.instantiate(this.pokePrefab);//生成
        this.pokePlace.addChild(poke_left, 1);
        let label = poke_left.getChildByName('numLabel').getComponent(cc.Label);//获取子节点中的一个label组件
        label.string = this.getPokeNum(pokeNum);//方法从数组中随机获取一个数字返回并赋值
        poke_left.scale = 0.8;
        poke_left.x = -60;
        // poke = poke_left
        poke.item = poke_left;//存一波对象信息
        poke.num = label.string;
        this.pokeArr.push(poke);
    },
    //从数组中随机取出一个
    getPokeNum:function(Arr){
        let a = Arr.length;
        let b = Math.floor(Math.random()*a);
        return Arr[b]
    },
    
  • 3:拖动逻辑处理
    -在拖动中,只能拖动右边的牌,而左边的牌无法拖动,需要在牌的位置改变后关闭触摸事件以及给新牌一个触摸事件。需要注意在某个区域放开后要放置牌的位置,牌不能超出一定数量
    //代码如下
    //添加触摸
    addListener:function(){
        if(this.pokeArr.length>0){
            this.choosePoke = this.pokeArr.shift().item;//从牌组里拿出第一个,就是右边的牌
            this.choosePoke.on("touchstart",this.touchStart,this,true);
            this.choosePoke.on("touchmove",this.touchMove,this,true);
            this.choosePoke.on("touchend",this.touchEnd,this,true);
            this.choosePoke.zIndex = 10;//节点走到右边去
            this.choosePoke.scale =1;
            this.choosePoke.setPosition(0,0)
            this.choosePoke._touchListener.setSwallowTouches(false);
        }
        
    },
    //注销触摸
    removeListener:function(){
        if(this.choosePoke){
            this.choosePoke.off("touchstart",this.touchStart,this,true);
            this.choosePoke.off("touchmove",this.touchMove,this,true);
            this.choosePoke.off("touchend",this.touchEnd,this,true);
            this.choosePoke.zIndex = 0;
            this.choosePoke = null;
        }
        
    },
    touchStart:function(){},
    touchMove:function(event){
        if(this.choosePoke){//摸到牌了
            this.choosePoke.x+=event.getDelta().x;
            this.choosePoke.y+=event.getDelta().y;
            let touchPos = this.choosePoke.convertToWorldSpaceAR(cc.v2(0,0));
            for(let blockNode of this.block){//获取几个放置区域
                let posInNode = this.worldConvertLocalPoint(blockNode.item,touchPos);//转换坐标系
                let blockSize = blockNode.item.getContentSize();
                // let blockSpace = (blockSize.height-this.choosePoke.height)/(blockRow-1) || 30;
                let rect = cc.rect(0,0,blockSize.width,blockSize.height);
                if(rect.contains(posInNode)){//牌进了某个放置区域了
                    cc.log(blockNode.item)
                    blockNode.item.color = cc.color(236,240,241,255);//该放置区域变色提醒
                }else{
                    blockNode.item.color = cc.color(152,152,152,255);
                }
            }
        }
    },
    touchEnd:function(){
        if(this.choosePoke){
        let touchPos = this.choosePoke.convertToWorldSpaceAR(cc.v2(0,0));
        for(let blockNode of this.block){
            let posInNode = this.worldConvertLocalPoint(blockNode.item,touchPos);
            let blockSize = blockNode.item.getContentSize();
            let blockSpace = (blockSize.height-this.choosePoke.height)/(blockRow-1) || 30;
            let rect = cc.rect(0,0,blockSize.width,blockSize.height);
            if(rect.contains(posInNode)){//牌进了放置区域松手
                if(blockNode.fill.length>=blockRow) return;//如果当前区域牌数量超出最大允许长度
                this.choosePoke.parent = blockNode.item;//换父节点
                blockNode.fill.push(this.choosePoke);//将当前牌放入该区域数组中
                let a = blockNode.fill.length;//当前牌是第几个,需要根据这个变量计算位置
                this.choosePoke.setPosition(cc.v2(0,0));//放置到中点位置
                cc.tween(this.choosePoke)
                    .to(0.2, { position: cc.v2(0,blockSize.height/2 - this.choosePoke.height/2-(a-1)*blockSpace)})//去到指定的位置
                    .to(0.1)
                    .call(()=>{
                        blockNode.fill = this.checkAdd(blockNode.fill);//缓动完毕。检查合成
                        blockNode.item.color = cc.color(152,152,152,255);//放置区域颜色变回
                    })
                    .start();
                // this.choosePoke.setPosition(0,blockSize.height/2 - this.choosePoke.height/2-(a-1)*blockSpace);
                
                //刷新注册事件
                this.removeListener();
                this.addListener();
                this.createLeft();//再生成一个左边的
                return;
            }else{
    
            }
            //没放进去,回原位
            this.choosePoke.setPosition(0,0);
        }
    
        }
    },
    
  • 4:合成处理
    -在合成中一般会处理一整个数组,但我这里只处理数组的倒数第一位和倒数第二位,若合成成功,那么再处理一次新的倒数第一位和倒数第二位
    在这里插入图片描述
    //代码如下
        //处理卡牌合成的问题
    checkAdd:function(arr){
        cc.log(arr[0].getChildByName('numLabel').getComponent(cc.Label));
        if(arr.length<=1) return arr;//如果只有一个卡牌,不处理合成
        let index = arr.length;//数组长度
        // 从数组末尾往前判断,若合并那么再判断一次
        if(arr[index-1].getChildByName('numLabel').getComponent(cc.Label).string == arr[index-2].getChildByName('numLabel').getComponent(cc.Label).string)
        {
            let num = arr[index-1].getChildByName('numLabel').getComponent(cc.Label).string
            arr[index-2].getChildByName('numLabel').getComponent(cc.Label).string = Number(num)*2;
            arr[index-1].removeFromParent();
            let max = Math.max.apply(null,pokeNum);//获取数组中最大的数字
            if(Number(num)*2>max && Number(num)*2<=64){//生成了新的数字,并且大于最大的数字,小于64
                pokeNum.push(Number(num)*2);//放入数组
            }
            arr[index-1] = null;
            let newArr = this.removeItemFromArray(arr[index-1],arr);//从节点数组中删除节点
            if(newArr.length>1){//若剩余数组长度为2个及以上
                newArr = this.checkAdd(newArr);//再处理一次合成
            }
            //判断消除
            return newArr;
        }else{
            return arr;
        }
        //!!!注意返回新的数组
    },
    //从数组中删除元素
    removeItemFromArray: function (item, itemArr) {
        return itemArr.filter(value => {
            return value !== item;
        })
    },
    
    
    到此,就完成了该游戏的大部分逻辑,后续会在其中加入道具功能供使用
    在这里插入图片描述
    欢迎各位观众姥爷指出不足之处以及提供精彩思路
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蟹 !

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值