一、算法思路
- 递归实现思路:
每一步迭代分为以下几种情况进行处理:
a. 移动到顶:结束迭代;
b. 当前数字为空:结束迭代;
c. 移动方向上前一个数字格为空:向该方向移动;
d. 移动方向上前一个数字格相同:合并,结束迭代;
e. 移动方向上前一个数字格不同:结束迭代。
二、算法框架
- 按照以上思路先写好算法框架。
move()方法
即移动函数,toMove数组
即要移动的数字块,通过循环遍历将非空的数字块存储在toMove数组中,counter
用于统计完成移动的数字块的个数,接下来调用toMove.length
次move()方法
,每次移动完需要调用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() {
},
三、代码补完
- 首先编写
doMove()函数
表示block实体的移动动画,使用cc.tween()方法
先在指定时间内移动到的位置,然后调用回调函数。
doMove(block, position, callback) {
cc.tween(block)
.to(MOVE_DURATION, { position })
.call(() => {
callback && callback()
})
.start();
},
- 在
moveLeft()方法
中,先定义一个标签hasMoved
标识往左滑动这个操作是否有导致数字块的变化,然后对这个move方法
按照之前的算法思路分五种情况进行讨论:
a. 移动到顶 & b. 当前数字为空:结束迭代;
c. 移动方向上前一个数字格为空:向该方向移动。将当前block
与data
与移动方向上前一格绑定,当前格清零,并调用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) {
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]) {
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);
}
});
}
},
- 定义
afterMove(hasMoved)方法
,根据hasMoved为true
有移动操作,调用addBlock()
随机生成新的数字快。
afterMove(hasMoved) {
if (hasMoved) {
this.addBlock();
}
},
- 预览可得。
- 按照相同思路可将四个
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)) {
if (vec.x < 0) {
this.moveDirection('left');
} else {
this.moveDirection('right');
}
} else {
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) {
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]) {
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);
}
});
}
},
- 预览可得。