返回

游戏创作之 Puzzle Game:Vue 实现一个拼图游戏

前端

Puzzle Game:Vue 实现一个拼图游戏

很久之前,曾有人提议模仿鹰脚网络首页左下角那个拼图小游戏。那天晚上睡觉的时候在床上想了一下,大致 get 到了它内部实现的原理,于是就干脆动手实践一番,现在也顺道写一篇博客记录下实现思路和中间遇到的一些问题。

实现原理
以下用到了很多DOM和JS操作。Vue实例作为容器,用来盛放一个个“拼图块”组件。拼图块的每一个实例都是一个长宽相等的小正方形div,里面放一张小图片,这些小图片被随机打乱,点击其中任意一个,可以与相邻拼图块互换位置。这样一直操作,直到恢复成游戏开始时拼图图片的原貌。

1. 搭建基本结构

为了实现这个游戏,我们需要搭建一个基本的结构。这个结构包括:

  • 游戏棋盘:这是一个包含所有拼图块的容器。
  • 拼图块:这是游戏的基本单元。每个拼图块都是一个包含一张图片的小正方形。
  • 控制拼图块移动的函数:这些函数允许玩家将拼图块移动到新的位置。
  • 判断游戏是否结束的函数:这个函数检查游戏是否已经完成。

2. 创建游戏棋盘

游戏棋盘是包含所有拼图块的容器。我们可以使用 Vue.js 的 <div> 组件来创建游戏棋盘。

<div id="game-board">
  <!-- 拼图块将被放置在这里 -->
</div>

3. 创建拼图块

拼图块是游戏的基本单元。每个拼图块都是一个包含一张图片的小正方形。我们可以使用 Vue.js 的 <div> 组件来创建拼图块。

<div class="puzzle-piece">
  <img src="image.png" alt="拼图块图片">
</div>

4. 控制拼图块移动

我们可以使用 Vue.js 的 v-on:click 指令来控制拼图块的移动。当玩家点击一个拼图块时,该指令将触发一个函数,该函数将移动拼图块到新的位置。

<div class="puzzle-piece" v-on:click="movePiece">
  <img src="image.png" alt="拼图块图片">
</div>
// 移动拼图块的函数
movePiece(event) {
  // 获取被点击的拼图块
  const piece = event.target;

  // 获取被点击的拼图块的位置
  const position = {
    x: piece.offsetLeft,
    y: piece.offsetTop
  };

  // 获取相邻的拼图块的位置
  const adjacentPositions = [
    { x: position.x - 100, y: position.y },
    { x: position.x + 100, y: position.y },
    { x: position.x, y: position.y - 100 },
    { x: position.x, y: position.y + 100 }
  ];

  // 循环相邻的拼图块,找到一个可以移动到的位置
  for (const adjacentPosition of adjacentPositions) {
    // 检查相邻位置是否为空
    if (document.getElementById(adjacentPosition.x + ',' + adjacentPosition.y) === null) {
      // 将被点击的拼图块移动到相邻位置
      piece.style.left = adjacentPosition.x + 'px';
      piece.style.top = adjacentPosition.y + 'px';

      // 结束循环
      break;
    }
  }
}

5. 判断游戏是否结束

我们可以使用 Vue.js 的 computed 属性来判断游戏是否结束。当游戏结束时,该属性将返回 true,否则返回 false

// 判断游戏是否结束的计算属性
isGameOver() {
  // 获取所有拼图块的位置
  const pieces = document.querySelectorAll('.puzzle-piece');

  // 循环拼图块,检查是否都已归位
  for (const piece of pieces) {
    // 获取拼图块的位置
    const position = {
      x: piece.offsetLeft,
      y: piece.offsetTop
    };

    // 获取拼图块的正确位置
    const correctPosition = {
      x: piece.dataset.x,
      y: piece.dataset.y
    };

    // 检查拼图块是否已归位
    if (position.x !== correctPosition.x || position.y !== correctPosition.y) {
      // 返回 false,表示游戏尚未结束
      return false;
    }
  }

  // 返回 true,表示游戏已结束
  return true;
}

6. 实现游戏

现在,我们已经搭建好了游戏的基本结构,并创建了控制拼图块移动和判断游戏是否结束的函数。接下来,我们可以实现游戏了。

<div id="app">
  <div id="game-board">
    <puzzle-piece v-for="piece in pieces" :piece="piece" @move-piece="movePiece"></puzzle-piece>
  </div>
  <div v-if="isGameOver">
    <h1>游戏结束!</h1>
  </div>
</div>
// Vue 实例
const app = new Vue({
  el: '#app',
  data: {
    pieces: [
      { x: 0, y: 0, image: 'image1.png' },
      { x: 100, y: 0, image: 'image2.png' },
      { x: 200, y: 0, image: 'image3.png' },
      { x: 0, y: 100, image: 'image4.png' },
      { x: 100, y: 100, image: 'image5.png' },
      { x: 200, y: 100, image: 'image6.png' },
      { x: 0, y: 200, image: 'image7.png' },
      { x: 100, y: 200, image: 'image8.png' },
      { x: 200, y: 200, image: 'image9.png' }
    ]
  },
  methods: {
    movePiece(event) {
      // 获取被点击的拼图块
      const piece = event.target;

      // 获取被点击的拼图块的位置
      const position = {
        x: piece.offsetLeft,
        y: piece.offsetTop
      };

      // 获取相邻的拼图块的位置
      const adjacentPositions = [
        { x: position.x - 100, y: position.y },
        { x: position.x + 100, y: position.y },
        { x: position.x, y: position.y - 100 },
        { x: position.x, y: position.y + 100 }
      ];

      // 循环相邻的拼图块,找到一个可以移动到的位置
      for (const adjacentPosition of adjacentPositions) {
        // 检查相邻位置是否为空
        if (document.getElementById(adjacentPosition.x + ',' + adjacentPosition.y) === null) {
          // 将被点击的拼图块移动到相邻位置
          piece.style.left = adjacentPosition.x + 'px';
          piece.style.top = adjacentPosition.y + 'px';

          // 结束循环
          break;
        }
      }
    }
  },
  computed: {
    isGameOver() {
      // 获取所有拼图块的位置
      const pieces = document.querySelectorAll('.puzzle-piece');

      // 循环拼图块,检查是否都已归位
      for (const piece of pieces) {
        // 获取拼图块的位置
        const position = {
          x: piece.offsetLeft,
          y: piece.offsetTop
        };

        // 获取拼图块的正确位置
        const correctPosition = {
          x: piece.dataset.x,
          y: piece.dataset.y
        };

        // 检查拼图块是否