周末在家玩别人的小游戏时发现一个比较有意思的休闲游戏,这里实现其中主要的逻辑,代码基本注释都有,比较清晰
效果如下:
- 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; }) },
欢迎各位观众姥爷指出不足之处以及提供精彩思路