CocosCreator项目实战(07)(移动与合并)


文章目录

  • 一、算法思路
  • 二、算法框架
  • 三、代码补完

一、算法思路
  1. 递归实现思路:
    每一步迭代分为以下几种情况进行处理:
    a. 移动到顶:结束迭代;
    b. 当前数字为空:结束迭代;
    c. 移动方向上前一个数字格为空:向该方向移动;
    d. 移动方向上前一个数字格相同:合并,结束迭代;
    e. 移动方向上前一个数字格不同:结束迭代。
二、算法框架
  1. 按照以上思路先写好算法框架。
    move()方法即移动函数,toMove数组即要移动的数字块,通过循环遍历将非空的数字块存储在toMove数组中,counter用于统计完成移动的数字块的个数,接下来调用toMove.lengthmove()方法,每次移动完需要调用afterMove()方法用于生成新的数字块。
moveLeft() { console.log('move left'); let move = (x, y, callback) => {}; let toMove = []; for (let i = 0; i < ROWS; ++i) { for (let j = 0; j < ROWS; ++j) { if (this.data[i][j] != 0) { toMove.push({ x: i, y: j }); } } } let counter = 0; for (let i = 0; i < toMove.length; ++i) { move(toMove[i].x, toMove[i].y, () => { counter++; if (counter == toMove.length) { this.afterMove(); } }); } },afterMove() {},

三、代码补完
  1. 首先编写doMove()函数表示block实体的移动动画,使用cc.tween()方法先在指定时间内移动到的位置,然后调用回调函数。
doMove(block, position, callback) { cc.tween(block) .to(MOVE_DURATION, { position }) .call(() => { callback && callback() }) .start(); },

  1. moveLeft()方法中,先定义一个标签hasMoved标识往左滑动这个操作是否有导致数字块的变化,然后对这个move方法按照之前的算法思路分五种情况进行讨论:
    a. 移动到顶 & b. 当前数字为空:结束迭代;
    c. 移动方向上前一个数字格为空:向该方向移动。将当前blockdata与移动方向上前一格绑定,当前格清零,并调用doMove()函数完成实体移动动画,最后hasMoved标签置为true表示有数字块的变化;
    d. 移动方向上前一个数字格相同:合并。将data * 2与移动方向上前一格绑定,当前格清零,当前格block置为null,前一个生成新的拥有data * 2值的数字块,并调用doMove()函数完成实体移动动画,最后hasMoved标签置为true表示有数字块的变化;
    e. 移动方向上前一个数字格不同:结束迭代。
moveLeft() { console.log('move left'); let hasMoved = false; let move = (x, y, callback) => { if (y == 0 || this.data[x][y] == 0) { callback && callback(); return; } else if (this.data[x][y - 1] == 0) { // Move let block = this.blocks[x][y]; let position = this.positions[x][y - 1]; this.blocks[x][y - 1] = block; this.data[x][y - 1] = this.data[x][y]; this.data[x][y] = 0; this.blocks[x][y] = null; this.doMove(block, position, () => { move(x, y - 1, callback); }); hasMoved = true; } else if (this.data[x][y - 1] == this.data[x][y]) { // Merge let block = this.blocks[x][y]; let position = this.positions[x][y - 1]; this.data[x][y - 1] *= 2; this.data[x][y] = 0; this.blocks[x][y] = null; this.blocks[x][y - 1].getComponent('block').setNumber(this.data[x][y - 1]); this.doMove(block, position, () => { block.destroy(); callback && callback(); }); hasMoved = true; } else { callback && callback(); return; } }; ... let counter = 0; for (let i = 0; i < toMove.length; ++i) { move(toMove[i].x, toMove[i].y, () => { counter++; if (counter == toMove.length) { this.afterMove(hasMoved); } }); } },

  1. 定义afterMove(hasMoved)方法,根据hasMoved为true有移动操作,调用addBlock()随机生成新的数字快。
afterMove(hasMoved) { if (hasMoved) { this.addBlock(); } },

  1. 预览可得。
CocosCreator项目实战(07)(移动与合并)
文章图片

  1. 按照相同思路可将四个move()方法整合为一个moveDirection(direction)方法。首先修改touchEnd(event)函数,在四个方向上均调用moveDirection()函数但传入不同的参数。而后修改moveLeft()方法moveDirection(direction)方法
touchEnd(event) { ... if (vec.mag() > MIN_LENGTH) { if (Math.abs(vec.x) > Math.abs(vec.y)) { // Horizontal if (vec.x < 0) { this.moveDirection('left'); } else { this.moveDirection('right'); } } else { // Vertical if (vec.y > 0) { this.moveDirection('up'); } else { this.moveDirection('down'); } } } }, ... moveDirection(direction) { console.log('move ' + direction); let tags = [{ x: 0, y: -1 }, { x: 0, y: 1 }, { x: 1, y: 0 }, { x: -1, y: 0 }]; let hasMoved = false; let move = (x, y, callback) => { let condition, tag; switch (direction) { case 'left': tag = tags[0]; condition = (y == 0); break; case 'right': tag = tags[1]; condition = (y == ROWS - 1); break; case 'up': tag = tags[2]; condition = (x == ROWS - 1); break; case 'down': tag = tags[3]; condition = (x == 0); break; } let destX = x + tag.x; let destY = y + tag.y; if (condition || this.data[x][y] == 0) { callback && callback(); return; } else if (this.data[destX][destY] == 0) { // Move let block = this.blocks[x][y]; let position = this.positions[destX][destY]; this.blocks[destX][destY] = block; this.data[destX][destY] = this.data[x][y]; this.data[x][y] = 0; this.blocks[x][y] = null; this.doMove(block, position, () => { move(destX, destY, callback); }); hasMoved = true; } else if (this.data[destX][destY] == this.data[x][y]) { // Merge let block = this.blocks[x][y]; let position = this.positions[destX][destY]; this.data[destX][destY] *= 2; this.data[x][y] = 0; this.blocks[x][y] = null; this.blocks[destX][destY].getComponent('block').setNumber(this.data[destX][destY]); this.doMove(block, position, () => { block.destroy(); callback && callback(); }); hasMoved = true; } else { callback && callback(); return; } }; let toMove = []; switch (direction) { case 'left': for (let i = 0; i < ROWS; ++i) { for (let j = 0; j < ROWS; ++j) { if (this.data[i][j] != 0) { toMove.push({ x: i, y: j }); } } } break; case 'right': for (let i = 0; i < ROWS; ++i) { for (let j = ROWS - 1; j >= 0; --j) { if (this.data[i][j] != 0) { toMove.push({ x: i, y: j }); } } } break; case 'up': for (let i = ROWS - 1; i >= 0; --i) { for (let j = 0; j < ROWS; ++j) { if (this.data[i][j] != 0) { toMove.push({ x: i, y: j }); } } } break; case 'down': for (let i = 0; i < ROWS; ++i) { for (let j = 0; j < ROWS; ++j) { if (this.data[i][j] != 0) { toMove.push({ x: i, y: j }); } } } break; }let counter = 0; for (let i = 0; i < toMove.length; ++i) { move(toMove[i].x, toMove[i].y, () => { counter++; if (counter == toMove.length) { this.afterMove(hasMoved); } }); } },

  1. 预览可得。
【CocosCreator项目实战(07)(移动与合并)】CocosCreator项目实战(07)(移动与合并)
文章图片

    推荐阅读