● Github上的代码,不能进行合并操作,修改以后,功能类似2048,空白块赏随机位置,生成2,可以往左、右、上、下滑动,数字会朝着指定方向运动,相邻元素如果相同,则合并。
游戏代码参考:https://github.com/potato47/1024
● 游戏分3个场景,game、sleep、success,sleep是不玩显示的,success是成功显示的,game是游戏核心场景,玩游戏都在此场景进行。
● 游戏的核心算法在Map脚本上,通过滑动结束点和起始点,判断滑动的方向,可以向左、右、上、下滑动,滑动后执行相应的逻辑onLeftSlide、onRightSlide、onUpSlide、onDownSlide,根据方向进行合并操作,相邻的元素,如果是相同的则合并,如果是空的,则向滑动方向移动。
● 核心的算法mergeArray,对传入的数组往右移动,然后相同的合并。
● 如四格的数字分别是[2,0,0,2],往右滑动以后,就会变成[0,0,2,2],最右边的相同,就执行合并操作,最终变成[0,0,0,4]。
● 又如[2,0,2,2],第一步移动后变成[0,2,2,2],从最后侧开始合并,合并第一步变成[0,2,0,4],再移动变成[0,0,2,4]。
● 类似上述操作,无论是向上、下、左、右滑动,只需要改变传入的数组元素的顺序即可。
//---------------Map.js------------------------
cc.Class({
extends: cc.Component,
properties: {
tilePrefab: cc.Prefab,
tileLayer: cc.Node,
},
// use this for initialization
onLoad: function () {
cc.map = this;
this.mapWidth = this.node.width;
this.tileWidth = this.mapWidth / 4;
this.g = this.getComponent(cc.Graphics);
this.touchStartPosition = cc.v2();
this.touchEndPosition = cc.v2();
this.node.on(cc.Node.EventType.TOUCH_START, (event) => {
this.touchStartPosition = event.getLocation();
});
this.node.on(cc.Node.EventType.TOUCH_END, (event) => {
this.touchEndPosition = event.getLocation();
let offsetX = this.touchEndPosition.x - this.touchStartPosition.x;
let offsetY = this.touchEndPosition.y - this.touchStartPosition.y;
if (Math.abs(offsetX) > Math.abs(offsetY)) {
if (offsetX > 15) {
this.onRightSlide();
cc.log('right');
} else if (offsetX < -15) {
this.onLeftSlide();
cc.log('left');
}
} else {
if (offsetY > 15) {
this.onUpSlide();
cc.log('up');
} else if (offsetY < -15) {
this.onDownSlide();
cc.log('down');
}
}
});
this.drawBg();
this.initTiles();
this.mergeArray([0,0,2,8]);
},
/**
* @description: 合并arr
* @param {array} arr
* @return:
*/
mergeArray(arr){
if(arr.length <= 0){
return;
}
cc.log('#1', arr);
// 按照顺序取出非0值
let src = [];
for(let i = 0; i < arr.length; i++){
if(arr[i] != 0){
src.push(arr[i]);
}
}
// 模拟栈
let stack = [];
while(src.length > 0){
// 栈是空或栈顶元素和源数据最后一个不一样
if(stack.length <= 0 || stack[0] != src[src.length - 1]){
stack.unshift(src[src.length-1]);
src.splice(src.length -1, 1);
}
// 栈顶出栈
else{
src[src.length-1] = src[src.length-1] * 2;
stack.splice(0, 1);
}
}
cc.log('#2', stack);
return stack;
},
onLeftSlide() {
// 判断是否有tile移动
let isMove = false;
for (let y = 0; y < 4; y++) {
let src = [];
for(let x = 3; x >= 0; x--){
src.push(this.tiles[x][y].number);
}
let stack = this.mergeArray(src);
// 有变化
if(stack.length != src.length){
for(let x = 0; x < 4; x++){
if(stack.length > 0){
this.tiles[x][y].number = stack[stack.length - 1];
stack.splice(stack.length-1, 1);
}
else{
this.tiles[x][y].number = 0;
}
}
isMove = true;
}
}
// 没变化
if(!isMove){
return;
}
if (isMove) {
this.newTile();
this.judgeOver();
}
},
onRightSlide() {
// 判断是否有tile移动
let isMove = false;
for (let y = 0; y < 4; y++) {
let src = [];
for(let x = 0; x < 4; x++){
src.push(this.tiles[x][y].number);
}
let stack = this.mergeArray(src);
// 有变化
if(stack.length != src.length){
for(let x = 3; x >= 0; x--){
if(stack.length > 0){
this.tiles[x][y].number = stack[stack.length - 1];
stack.splice(stack.length-1, 1);
}
else{
this.tiles[x][y].number = 0;
}
}
isMove = true;
}
}
// 没变化
if(!isMove){
return;
}
//有tile移动才添加新的tile
if (isMove) {
this.newTile();
this.judgeOver();
}
},
onDownSlide() {
// 判断是否有tile移动
let isMove = false;
for (let x = 0; x < 4; x++) {
let src = [];
for(let y = 3; y >= 0; y--){
src.push(this.tiles[x][y].number);
}
let stack = this.mergeArray(src);
// 有变化
if(stack.length != src.length){
for(let y = 0; y < 4; y++){
if(stack.length > 0){
this.tiles[x][y].number = stack[stack.length - 1];
stack.splice(stack.length-1, 1);
}
else{
this.tiles[x][y].number = 0;
}
}
isMove = true;
}
}
// 没变化
if(!isMove){
return;
}
if (isMove) {
this.newTile();
this.judgeOver();
}
},
onUpSlide() {
// 判断是否有tile移动
let isMove = false;
for (let x = 0; x < 4; x++) {
let src = [];
for(let y = 0; y < 4; y++){
src.push(this.tiles[x][y].number);
}
let stack = this.mergeArray(src);
// 有变化
if(stack.length != src.length){
for(let y = 3; y >= 0; y--){
if(stack.length > 0){
this.tiles[x][y].number = stack[stack.length - 1];
stack.splice(stack.length-1, 1);
}
else{
this.tiles[x][y].number = 0;
}
}
isMove = true;
}
}
// 没变化
if(!isMove){
return;
}
if (isMove) {
this.newTile();
this.judgeOver();
}
},
drawBg() {
this.g.rect(0, 0, this.node.width, this.node.height);
this.g.fillColor = new cc.Color().fromHEX('#0000ff');//cc.hexToColor('#ffffff');
this.g.stroke();
this.g.fill();
this.g.strokeColor = cc.Color.BLACK;
this.g.lineWidth = 10;
for (let x = 0; x < 5; x++) {
this.g.moveTo(x * this.tileWidth, 0);
this.g.lineTo(x * this.tileWidth, this.mapWidth);
}
for (let y = 0; y < 5; y++) {
this.g.moveTo(0, y * this.tileWidth);
this.g.lineTo(this.mapWidth, y * this.tileWidth);
}
this.g.stroke();
},
judgeOver() {
for(let x = 0; x < 4;x++){
for(let y = 0; y < 4; y++) {
if(this.tiles[x][y].number === 1024) {
cc.director.loadScene('success');
}
}
}
},
initTiles(tileWidth) {
this.tileLayer.removeAllChildren();
this.tiles = [];
this.zeroTiles = [];
for (let x = 0; x < 4; x++) {
this.tiles[x] = [];
for (let y = 0; y < 4; y++) {
let tileNode = cc.instantiate(this.tilePrefab);
this.tileLayer.addChild(tileNode);
tileNode.x = x * this.tileWidth + this.tileWidth / 2;
tileNode.y = y * this.tileWidth + this.tileWidth / 2;
let tile = tileNode.getComponent('Tile');
tile.init(x, y, 0);
this.tiles[x][y] = tile;
this.zeroTiles.push(tile);
}
}
for (let i = 0; i < 2; i++) {
this.newTile();
}
},
newTile() {
this.zeroTiles = [];
for (let x = 0; x < 4; x++) {
for (let y = 0; y < 4; y++) {
if (this.tiles[x][y].number === 0) {
this.zeroTiles.push(this.tiles[x][y]);
}
}
}
let n = Math.floor(Math.random() * this.zeroTiles.length);
this.zeroTiles[n].randomNumber();
// this.zeroTiles[n].getComponent('Tile').randomNumber();
this.zeroTiles.splice(n, 1);
},
onBtnRetry() {
cc.director.loadScene('game');
},
onBtnSleep() {
cc.director.loadScene('sleep');
}
});
//---------------Tile.js------------------------
cc.Class({
extends: cc.Component,
properties: {
x: 0,
y: 0,
_number: 0,
number: {
set(number) {
if (number === this._number) return;
this._number = number;
if (number === 0) {
this.numberLabel.string = '';
} else {
this.numberLabel.string = number + '';
// let colorHex = Math.floor(Math.random() * 16777215) + 1;
// let color = cc.hexToColor('#' + colorHex.toString(16));
// this.node.color = color;
if(this.number > 0) {
this.node.color = cc.Color.RED;
}else{
this.node.color = cc.Color.BLUE;
// this.node.color = cc.Color.GREEN;
}
}
},
get() {
return this._number;
}
},
numberLabel: cc.Label,
},
// use this for initialization
onLoad: function () {
},
init(x, y, n) {
this.x = x;
this.y = y;
this.number = n;
},
randomNumber() {
this.number = 2;
// let n = Math.ceil(Math.random() * 2);
// if(n === 1) {
// this.number = 64;
// }else {
// this.number = -64;
// }
}
});
//---------------GameScene.js------------------------
cc.Class({
extends: cc.Component,
properties: {
// foo: {
// default: null, // The default value will be used only when the component attaching
// to a node for the first time
// url: cc.Texture2D, // optional, default is typeof default
// serializable: true, // optional, default is true
// visible: true, // optional, default is true
// displayName: 'Foo', // optional
// readonly: false, // optional, default is false
// },
// ...
},
// use this for initialization
onLoad: function () {
},
// called every frame, uncomment this function to activate update callback
// update: function (dt) {
// },
});
感谢:
本文转载自https://mp.weixin.qq.com/s/7sqizrU-hZmPOcweK0yPHQ这篇文章,这里感谢原作者对于技术的分享。
下载:
本文章源码和资源下载地址