先来看一下游戏效果

电脑端: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

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

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

  1. slider节点透明背景_【Cocos Creator 实战教程(1)】——人机对战五子棋(节点事件相关)...

    一.涉及知识点 场景切换 按钮事件监听 节点事件监听 节点数组 循环中闭包的应用 动态更换sprite图片 定时器 预制资源 二.步骤 2.1 准备工作 首先,我们要新建一个空白工程,并在资源管理器中 ...

  2. 【Cocos Creator 实战教程(1)】——人机对战五子棋(节点事件相关)

    整体思路 在15*15的棋盘上每一个可下棋子的地方都放置一个"隐形的棋子",当要在某个位置下子时就将该位置的棋子显示出来,在判断输赢逻辑里,我们根据这225个"隐形棋子& ...

  3. 【Cocos Creator实战教程(7)】——猴子摘月亮(平台动作,碰撞检测详解)

    最后一个寒假说没就没... 话说我等Creator 的物理引擎等了好久好久,终于......还是没等到...... 我们今天就用碰撞检测系统和一些算法简单的模拟一下2D平台动作的物理特性吧 先来看一下 ...

  4. Cocos Creator实战教程(5)】——打砖块(物理引擎,碰撞检测)

    1. 知识点 物理引擎 碰撞检测 2. 步骤 2.1 准备工作 搭一个游戏背景 2.2 小球运动 再建一个物理层,用来装游戏里的带有物理属性的东西,设置锚点为左下角 wall:墙//小球碰到就会反弹的 ...

  5. 【Cocos Creator实战教程(3)】——TiledMap(瓦片地图)组件

    1. 前言 瓦片地图是由一张一张的正方形小图片拼接成的地图,例如炸弹人,QQ堂都是非常典型的瓦片游戏.瓦片地图(Tile Map) 不但生成简单,并且可以灵活的用于Cocos2d-x引擎.不论你的游戏 ...

  6. 【Cocos Creator 实战教程(4)】——黄金矿工(上)(节点动作、碰撞体相关)

    准备工作: 我们新建一个工程,名字叫做GoldMiner,把相关资源导入,搭建一个游戏场景如下(灰色节点先不用看,那是后来加上的): 绳子伸缩思路: 在玩游戏时我们需要让绳子伸长去采矿,在制作游戏的时 ...

  7. 【Cocos Creator 实战教程(2)】——天天酷跑(动画、动作相关)

    转载请保留原文链接,个人公众号:xinshouit(新手程序员),欢迎关注 准备工作 把背景图拉长,很长很长的那种....一会我们要让它滑动起来 背景动画 为背景节点添加滚动动画 现在背景就循环滚动起 ...

  8. 【Cocos Creator 实战】06 - 如何给拼图游戏添加计时器

    文章目录 概览 主要内容 项目资源 开搞 项目结构 字体 如何控制节点的显示&隐藏 如何设置节点的相对位置 & 自动大小 & 对齐策略 如何防止节点的点击穿透 如何倒计时 总结 ...

  9. 【Cocos Creator 实战】02 - 给拼图游戏加上音乐和音效

    文章目录 概览 主要内容 项目资源 开搞 使用 AudioSource 播放(静态) 使用 AudioEngine 播放(静态 + 动态) 静态播放 动态播放 AudioSource 和 AudioE ...

最新文章

  1. TVS參数具体解释及选型应用
  2. ubuntu中安装hadoop集群
  3. YUDBModel【绿色插件】-对象序列化、反序列化、对象一键增删改查
  4. C++PrimerCH2
  5. java io流 教程_Java基础教程:IO流与文件基础
  6. 红帽资深解决方案架构师魏新宇:云原生应用构建之路
  7. autocad 如何摆正显示_如何在 VB 中连接 AutoCAD
  8. 关于Lodop打印控件
  9. TCP连接的99号和110号错误
  10. Android 命名规范 (提高代码可以读性) 转
  11. php 背单词系统_《PHP 编程词典(珍藏版)》
  12. Selenium 对元素element的操作举例
  13. 达“超人”水平?强化学习得这么用!
  14. APP抓包,针对 SSLPinning反爬
  15. 新版UNITY游戏(IL2CPP类型)使用内嵌型机器翻译插件XUnity.AutoTranslator的食用方法
  16. 生产制造行业ERP系统十大品牌
  17. 使用Excel 提取文本中的数字
  18. 则必有不完全相同的奇数排列对换为同一个偶排列
  19. python定积分1002无标题_python 求定积分和不定积分
  20. shell脚本运行报错: syntax error: unmatched ‘while‘

热门文章

  1. python 浮点数计算
  2. KY95 Old Bill
  3. HashMap底层红黑树原理(超详细图解)+手写红黑树代码
  4. 农业新机遇:新品牌与新模式
  5. js实现MAD图像识别算法
  6. 2022暑期杭电第七场
  7. CSS 中px、em、rem、%、vw、vh单位之间的区别详解【全网最全】
  8. 人生苦短我学Java-1-Helloword
  9. Scratch(二十四):垃圾分类
  10. OpenCV-Python 读取显示图像 | 五