相信大家都玩过一款经典的小游戏2048,下面我分享一下我实现这款小游戏思路(可能有更好的方法,欢迎大家留言)
数字的表示与更新
- 用一个长度为16的一维数组来表示数字矩阵,索引表示位置,值表示数字大小。
例如:
numbers = [4, 2, 4, 4, 0, 0, 2, 2, 0, 0, 0, 2, 4, 0, 0, 0] 值为零的数字隐藏。 每一次滑动后重新对numbers赋一次值。
向上滑动
-
假如进行一次上滑,效果是这样的(这里先不添加新数字): 我们可以看到:两个相同的数字相撞时,这两个数字相加。要怎么实现呢? -
先把长度为16的数组按顺序拆分为4个长度为4的数组并合并组成一个二维数组。 numbers = [4, 2, 4, 4, 0, 0, 2, 2, 0, 0, 0, 2, 4, 0, 0, 0] arr = [[4, 2, 4, 4],[0, 0, 2, 2], [0, 0, 0, 2], [4, 0, 0, 0]]
这样的话,arr的每一元素就表示数字矩阵的每一行(从上到下)。
- 判断第一行的数字如果和第二行的数字同一列是否相等或者有一个数字为零,如果是则相加,并把相加结果赋值给第一行,最后把第二行相加过的数字清零。
- 第二行和第三行、第三行和第四行也执行以上操作。
过程大致如下:
-
上述过程重复三次: 额。。。和结果不太一样。arr的正确结果应该是: [8, 2, 4, 4] [0, 0, 2, 4] [0, 0, 0, 0] [0, 0, 0, 0] 这是因为同一列的数字只能相加一次,所以 -
定义一个数组added,在数字相加的时候记录该数字的列数并存到added里,每次数字相加前检查added里面有没有该数字列数,如果有,就不相加了。(上述例子中added = [3]) -
最后把二维数组arr转为一维数组赋值给numbers,这样就完成了一次数字矩阵的更新了。 到这里一次上滑动作就完成了。
向下、左、右滑动
有了上滑的思路,其他方向滑动只是大同小异。
我们只需要改变二维数组arr向一位数组numbers取数字的顺序就行了。
所以滑动的行为可以封装成一个函数,根据参数判断是哪一个方向即可。 function move(direction){ … }
增加数字
在游戏开始的时候和一次滑动动作后,向为0的数字中随机选一个变为2
代码(vue)
<template>
<div class="play">
<div class="content" @touchstart="start" @touchend="end">
<div class="item" v-for="(item,index) in numbers" :key='index'>
<div :class="item===0?numberZeroClass:'number'"
:style="itemStyles[Math.log2(item)]">{{item}}</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
numbers: [],
numberZeroClass: 'number numberZero',
itemStyles:'color:#000; background:',
startX: '',
startY: '',
}
},
onLoad() {
this.numbers = [8, 2, 4, 4, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0]
this.itemStyles = [
'color:#000; background:#FFF3EE',
'color:#000; background:#FFDAC8',
'color:#000; background:#FFBD9D',
'color:#000; background:#FF9D6F',
'color:#000; background:#FF5809',
'color:#000; background:#FF8040',
'color:#fff; background:#F75000',
'color:#fff; background:#BB3D00',
'color:#fff; background:#842B00',
'color:#fff; background:#424200',
'color:#fff; background:#000079',
'color:#fff; background:#2F0000',
]
},
methods: {
fristNumber(){
this.numbers[Math.floor(Math.random()*16)] = 2
},
move(direction){
let arr = []
let numbers = this.numbers.slice(0)
let arrItem = []
switch(direction){
case 'up':{
console.log('up');
numbers.forEach((item, index) => {
for (let i = 0; i < this.numbers.length / 4; i++) {
arrItem.push(numbers.shift(index))
}
arr.push(arrItem)
arrItem = []
})
}break
case 'down':{
numbers.forEach((item, index) => {
for (let i = 0; i < this.numbers.length / 4; i++) {
arrItem.push(numbers.shift(index))
}
arr.unshift(arrItem)
arrItem = []
})
}break
case 'left':{
let c0 = [],c1 = [],c2 = [],c3 = []
numbers.forEach((item, index) => {
if(index % 4 === 0){
c0.push(item)
}else if(index % 4 === 1){
c1.push(item)
}else if(index % 4 === 2){
c2.push(item)
}else{
c3.push(item)
}
})
arr.push(c0,c1,c2,c3)
}break
case 'right':{
let c0 = [],c1 = [],c2 = [],c3 = []
numbers.forEach((item, index) => {
if(index % 4 === 0){
c0.push(item)
}else if(index % 4 === 1){
c1.push(item)
}else if(index % 4 === 2){
c2.push(item)
}else{
c3.push(item)
}
})
arr.push(c3,c2,c1,c0)
}break
default :
console.log('move parameter must one of up、down、left and right of sting type');
}
let arrItem1
let arrItem2
let added = []
for (let i = 0; i < 3; i++) {
arr.forEach((item2, index2) => {
if (index2 < arr.length - 1) {
arrItem1 = item2
arrItem2 = arr[index2 + 1]
arrItem1.forEach((item, index) => {
if (arrItem2[index] === 0 || item === 0) {
arrItem1[index] += arrItem2[index]
arrItem2[index] = 0
} else if (item === arrItem2[index] && item * arrItem2[index] !== 0 &&
added.indexOf(index) == -1) {
arrItem1[index] += arrItem2[index]
arrItem2[index] = 0
added.push(index)
}
})
}
})
}
let startNumber = this.numbers
if(direction === 'up'){
this.numbers = arr.flat()
}else if(direction === 'down'){
let numbers2 = []
arr.forEach((item, index)=>{
numbers2.push(arr[3-index])
})
this.numbers = numbers2.flat()
}else if(direction === 'left'){
let numbers3 = []
for (let i = 0; i < arr.length; i++) {
arr.forEach((item, index)=>{
numbers3.push(item[i])
})
}
this.numbers = numbers3.flat()
}else if(direction === 'right'){
let numbers4 = []
for (let i = 0; i < arr.length; i++) {
for (let k = 0; k < arr.length; k++){
numbers4.push(arr[3-k][i])
}
}
this.numbers = numbers4.flat()
}
let endNumber = this.numbers
if (startNumber.toString() !== endNumber.toString()) {
this.addNumber()
}
},
addNumber() {
let arrZeros = []
this.numbers.forEach((item, index) => {
if (item === 0) arrZeros.push(index)
})
let randomItem = arrZeros[Math.floor(Math.random() * arrZeros.length)]
this.numbers[randomItem] = 2
},
getNumberColor(){
},
start(e) {
this.startX = Math.floor(e.changedTouches[0].clientX)
this.startY = Math.floor(e.changedTouches[0].clientY)
},
end(e) {
let x = Math.floor(e.changedTouches[0].clientX) - this.startX
let y = Math.floor(e.changedTouches[0].clientY) - this.startY
if (x > 50 && 0 < y < 50) {
console.log('右滑')
this.move('right')
} else if (x < -50 && 0 < y < 50) {
console.log('左滑')
this.move('left')
} else if (0 < x < 50 && y < -50) {
console.log('上滑')
this.move('up')
} else if (0 < x < 50 && y > 50) {
console.log('下滑');
this.move('down')
}
}
},
}
</script>
<style lang="scss">
.play {
width: 100%;
.content {
display: flex;
justify-content: space-around;
box-sizing: border-box;
flex-wrap: wrap;
width: 750rpx;
height: 750rpx;
.item {
width: 23%;
height: 23%;
background: #fff;
.number {
color: #fff;
background: #f6ff43;
border-radius: 10%;
text-align: center;
line-height: 180rpx;
font-size: 25px;
font-weight: 600;
}
.numberZero {
background: #D1E9E9;
font-size: 0px;
}
}
}
}
</style>
|