vue3-2048小游戏

523 阅读2分钟

2048 小游戏前端开发

技术栈选取

vue3+vite+ts+tailwind

游戏规则

 游戏界面如下:

2048.jpg

​ 游戏界面由 4*4 的方格组成,每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块(2 或者 4),相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出 2048 这个数字就算成功,如果格子满了不能再滑动了则失败。

设计思路

布局

 分为三个部分,头部的 title,中间的游戏操作界面,底部的操作按钮(重新开始)以及得分。主要代码如下:

<div class="w-full h-full p-4 flex flex-col items-center">
  <header class="text-3xl">2048小游戏</header>
  <footer ref="target" class="m-4 w-[90%] max-w-[460px] h-[50%] max-h-[460px] p-[10px] bg-slate-300 flex flex-wrap justify-between items-center">
    <div
      v-for="item in arr"
      :key="item.index"
      :style="{ 'background-color': refreshColor(item.value) }"
      class="w-[23%] h-[23%] text-2xl flex items-center justify-center"
    >
      {{ item.value }}
    </div>
  </footer>
  <div>
    <button class="w-20 h-10 bg-orange-50" style="border: 1px solid red; border-radius: 5px" @click="init"> 重新开始 </button>
    当前得分:<span class="text-lg">{{ score }}</span>
  </div>
</div>

设计思路

  1. 4*4 的小正方形设计为一个数组,初始值设计为 0
  2. 空白的地方随机生成 2 或者 4:从数组中获取值为 0 的对象生成一个新的数组,从中随机选择一个,赋予值 2 或者 4。
  3. 监听操作:监听键盘的上下左右按钮;监听页面的滑动。
  4. 核心:数值的和并,把大数组分成 4 个小数组,每个小数组先把 0 去除,根据操作方向(上下左右),去合并数值,最后把数组补充 0(恢复成原本长度)。
  5. 判断输赢:赢,如果数组出现 2048 则胜利;输:格子满了,且上下左右没有可以合并的值。
for (let i = 0; i < 4; i++) {
  // 分解大数组为四个小数组,同时把值为0的去掉
  let itemArr: Array<number> = [arr.value[i * 4].value, arr.value[i * 4 + 1].value, arr.value[i * 4 + 2].value, arr.value[i * 4 + 3].value].filter(
    (item: number) => item != 0
  )
  const length = itemArr.length
  if (length > 1) {
    if (direction == 'right') {
      for (let j = length; j > 1; j--) {
        if (!itemArr[j - 1]) {
          continue
        }
        // 判断值是否相等,相等则合并
        if (itemArr[j - 1] == itemArr[j - 2]) {
          itemArr[j - 1] = 2 * itemArr[j - 1]
          score.value += itemArr[j - 1]
          if (itemArr[j - 1] === 2048) isWin = true
          itemArr[j - 2] = 0
        }
      }
    } else {
      for (let j = 0; j < length - 1; j++) {
        if (!itemArr[j]) {
          continue
        }
        if (itemArr[j] == itemArr[j + 1]) {
          itemArr[j] = 2 * itemArr[j]
          score.value += itemArr[j]
          if (itemArr[j] === 2048) isWin = true
          itemArr[j + 1] = 0
        }
      }
    }
  }
  itemArr = itemArr.filter((item: number) => item != 0)
  const finalLength = itemArr.length
  if (finalLength != 4) {
    for (let k = 0; k < 4 - finalLength; k++) {
      if (direction == 'right') {
        itemArr.unshift(0)
      } else {
        itemArr.push(0)
      }
    }
  }
  arr.value[i * 4].value = itemArr[0]
  arr.value[i * 4 + 1].value = itemArr[1]
  arr.value[i * 4 + 2].value = itemArr[2]
  arr.value[i * 4 + 3].value = itemArr[3]
}

源码地址

源码地址