首頁 > 軟體

利用Vue.js製作一個拼圖華容道小遊戲

2022-04-08 13:00:37

遊戲介紹

先看看介面

這是一個拼圖遊戲,可以自選難度和自選闖關圖片

遊戲開始後根據不同難度,生成與所選主圖 對應的 不同張數的 隨機順序的小圖,然後只要把亂序的小圖片還原成完整的圖片就闖關成功

遊戲區域有一個空白位置,可以用滑鼠點選空白位相鄰的圖片完成替換,也就是移動,也可以用鍵盤上下左右操作

遊戲好玩,可不要貪杯哦,學習也不能落下,不管什麼遊戲都一樣

這個雖然用到的技術很一般很簡單,多數還是普通的 JS,但是也花了不少時間,特別是圖片。確定整體風格,找背景圖、遊戲框。也是前兩天假期,喊我女朋友幫忙找圖片,也找了很多圖片讓她幫忙參考,畢竟她的審美比我強,我就粗漢子

核心思路

  • 遊戲等級(level),比如初級,等級數值定為3,遊戲介面就是三行三列,中級等級數值為4,遊戲介面就是四行四列,即當前等級的平方,就是小格子總數量
  • 遊戲開始後以格子總數量為最大值,來生成亂數的陣列 randomData,初級如:[3,1,7,2,4,8,6,5,9],遍歷生成小圖片,最大數值為空白格子,就是9
  • 並根據當前等級生成拼圖完成時的資料 finishData,初級如:123456789
  • 點選或鍵盤按鍵的時候將符合條件的,randomData 裡的目標格子和空白格子對應的值,交換,然後自動更新檢視,完成移動
  • 每走一步時,統計步數,並檢查 randomData().join('') == finishData,相等即拼圖完成

核心程式碼

注意看註釋哦

html

以下就是拼圖區域全部html,根據狀態 isStart 控制是否是處於遊戲狀態

<div class="stage">
  <div class="game-name" v-show="!isStart">華容道</div>
  <div class="content clearfix" v-show="isStart">
    <div
      v-for="item in randomData"
      :key="item"
      :class="`img${level}`"
      @click="handleMove(item)"
    >
      <el-image
        v-if="item != randomData.length"
        :src="getSmallImg(`${gameImg}/${level}/${item}.jpg`)"
      ></el-image>
    </div>
  </div>
</div>

getSmallImg 這個方法是用於動態引入圖片的,畢竟不是 webpack,沒有 require 那麼方便

// 獲取當前遊戲小圖片
export const getSmallImg = (path: string) => {
  return new URL(`../assets/images/${path}`, import.meta.url).href
}

games 類

js 部分主要是封裝了一個類,方便統一管理操作

// 拼圖類
class Puzzle implements IPuzzle {
  isStart = false  // 遊戲狀態
  randomData: Array<number> = [] // 亂序的,對應當前遊戲小圖片張數的陣列
  finishData = "" // 正序的,拼圖完成時的排序,用來對比
  gameImg = ""  // 遊戲主圖
  level = 3 // 遊戲等級
  step = 0 // 遊戲步數
  constructor() {}
  // 初始化
  init({ gameImg, level }: IMode) {
    this.step = 0
    this.level = level
    this.gameImg = gameImg
    // 生成當前遊戲亂數陣列
    this.randomData = this.getRandomData()
    this.isStart = !this.isStart
    // 如果是開始遊戲,就計算出拼圖完成時的資料
    if (this.isStart) this.finishData = this.getFinishData()
  }
  // 移動圖片
  move(idx: number) {}
  // 鍵盤事件
  onKeyDown(code: number){}
  // 檢查是否拼圖完成
  finish() {}
  // 生成小圖片數量陣列
  getRandomData(){}
}

生成隨機圖片數量

就是在點選開始遊戲的時候會執行 getRandomData,生成亂數陣列,然後 DOM 部分就遍歷這個生成的亂數陣列,渲染切碎了的小圖片

// 生成小圖片數量陣列
getRandomData() {
    // 亂數集合
    let randomArr = []
    // 根據遊戲等級生成最大值,減1是因為最大值保留作空白位放最後
    let max = Math.pow(this.level, 2) - 1
    while (randomArr.length < max) {
      // 生成一個最大值範圍內的亂數
      let random = Math.floor(Math.random() * max) + 1
      if (randomArr.indexOf(random) == -1) {
        // 沒有重複的就新增
        randomArr.push(random)
      }
    }
    randomArr.push(max + 1) // 新增最大數位作為最後的空白位
    return randomArr // 如:[3, 1, 7, 2, 4, 8, 6, 5, 9]
}

移動圖片

接收一個引數,就是在遍歷亂數陣列 randomData 的時候,對應每個圖片的值,滑鼠點選的時候拿到這個值

// 移動圖片
move(idx: number) {
    let level = this.level
    let target = this.randomData.indexOf(idx) // 當前點選位置下標
    let space = this.randomData.indexOf(Math.pow(level, 2)) // 空白位置下標

    // 過濾一下,不然空白位置在最左邊時點選右邊上一個數位時也能實現交換
    // 以及空白位置在最右邊點選左邊下一個數位時也能實現交換
    let condition =
      (space % level == 0 && target % level == level - 1) ||
      (space % level == level - 1 && target % level == 0)
      
    // 如果能交換
    if (!condition) {
      // 並且點選目標的,上或下或左或右是空白位,就交換位置
      if (
        target == space - level ||
        target == space + level ||
        target == space - 1 ||
        target == space + 1
      ) {
          this.change(space, target)
      }
    }
}
// 動起來
change(space: number, target: number) {
    // 空白位置替換成目標位置
    this.randomData[space] = this.randomData[target]
    // 目標位置為最大值,實現交換
    this.randomData[target] = Math.pow(this.level, 2)
    // 步數
    this.step += 1
    // 檢查是否完成
    this.finish()
}

鍵盤事件

按下鍵盤上下左右的時候,判斷空格位置對應你按的那個方向能不能移動,符合條件就替換

// 鍵盤事件
onKeydown(code: number) {
    let level = this.level
    // 目標位置下標
    let target
    // 空白位置下標
    let space = this.randomData.indexOf(Math.pow(level, 2))
    // 上下左右
    switch (code) {
      case 37:
        target = space + 1
        if (space % level == level - 1) return
        this.change(space, target)
        break
      case 38:
        target = space + level
        if (target > this.randomData.length - 1) return
        this.change(space, target)
        break
      case 39:
        target = space - 1
        if (space % level == 0) return
        this.change(space, target)
        break
      case 40:
        target = space - level
        if (target < 0) return
        this.change(space, target)
        break
    }
}

拼圖完成

思路是把當前亂序的 randomData 轉為字串,和正序的 finishData 作對比,如果一樣了,就是拼圖完成了

// 檢查是否拼圖完成
finish() {
    // 如:'312' == '123'
    if (this.randomData.join("") == this.finishData) {
      ElMessageBox.alert(`恭喜你,闖關成功,僅用${this.step}步`, "提示", {
        confirmButtonText: "OK",
        callback: (action: Action) => {
          this.randomData = []
          this.step = 0
          this.isStart = false
        },
      })
    }
}
// 根據不同難度生成拼圖完成時的資料用來對比,判斷是否完成
// 比如初級難度就是:123456789
getFinishData(): string {
    let str = ""
    for (let i = 1, len = Math.pow(this.level, 2); i <= len; i++) {
      str += i
    }
    return str
}

結語

遊戲體驗地址(pc)

開源地址

以上就是利用Vue.js製作一個拼圖華容道小遊戲的詳細內容,更多關於Vue.js拼圖華容道的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com