利用Vue.js制作一個拼圖華容道小游戲
游戲介紹
先看看界面



這是一個拼圖游戲,可以自選難度和自選闖關(guān)圖片
游戲開始后根據(jù)不同難度,生成與所選主圖 對應(yīng)的 不同張數(shù)的 隨機順序的小圖,然后只要把亂序的小圖片還原成完整的圖片就闖關(guān)成功
游戲區(qū)域有一個空白位置,可以用鼠標(biāo)點擊空白位相鄰的圖片完成替換,也就是移動,也可以用鍵盤上下左右操作
游戲好玩,可不要貪杯哦,學(xué)習(xí)也不能落下,不管什么游戲都一樣
這個雖然用到的技術(shù)很一般很簡單,多數(shù)還是普通的 JS,但是也花了不少時間,特別是圖片。確定整體風(fēng)格,找背景圖、游戲框。也是前兩天假期,喊我女朋友幫忙找圖片,也找了很多圖片讓她幫忙參考,畢竟她的審美比我強,我就粗漢子
核心思路
- 游戲等級(level),比如初級,等級數(shù)值定為3,游戲界面就是三行三列,中級等級數(shù)值為4,游戲界面就是四行四列,即當(dāng)前等級的平方,就是小格子總數(shù)量
- 游戲開始后以格子總數(shù)量為最大值,來生成隨機數(shù)的數(shù)組
randomData,初級如:[3,1,7,2,4,8,6,5,9],遍歷生成小圖片,最大數(shù)值為空白格子,就是9 - 并根據(jù)當(dāng)前等級生成拼圖完成時的數(shù)據(jù)
finishData,初級如:123456789 - 點擊或鍵盤按鍵的時候?qū)⒎蠗l件的,
randomData里的目標(biāo)格子和空白格子對應(yīng)的值,交換,然后自動更新視圖,完成移動 - 每走一步時,統(tǒng)計步數(shù),并檢查
randomData().join('') == finishData,相等即拼圖完成
核心代碼
注意看注釋哦
html
以下就是拼圖區(qū)域全部html,根據(jù)狀態(tài) isStart 控制是否是處于游戲狀態(tài)
<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 這個方法是用于動態(tài)引入圖片的,畢竟不是 webpack,沒有 require 那么方便
// 獲取當(dāng)前游戲小圖片
export const getSmallImg = (path: string) => {
return new URL(`../assets/images/${path}`, import.meta.url).href
}games 類
js 部分主要是封裝了一個類,方便統(tǒng)一管理操作
// 拼圖類
class Puzzle implements IPuzzle {
isStart = false // 游戲狀態(tài)
randomData: Array<number> = [] // 亂序的,對應(yīng)當(dāng)前游戲小圖片張數(shù)的數(shù)組
finishData = "" // 正序的,拼圖完成時的排序,用來對比
gameImg = "" // 游戲主圖
level = 3 // 游戲等級
step = 0 // 游戲步數(shù)
constructor() {}
// 初始化
init({ gameImg, level }: IMode) {
this.step = 0
this.level = level
this.gameImg = gameImg
// 生成當(dāng)前游戲隨機數(shù)數(shù)組
this.randomData = this.getRandomData()
this.isStart = !this.isStart
// 如果是開始游戲,就計算出拼圖完成時的數(shù)據(jù)
if (this.isStart) this.finishData = this.getFinishData()
}
// 移動圖片
move(idx: number) {}
// 鍵盤事件
onKeyDown(code: number){}
// 檢查是否拼圖完成
finish() {}
// 生成小圖片數(shù)量數(shù)組
getRandomData(){}
}生成隨機圖片數(shù)量
就是在點擊開始游戲的時候會執(zhí)行 getRandomData,生成隨機數(shù)數(shù)組,然后 DOM 部分就遍歷這個生成的隨機數(shù)數(shù)組,渲染切碎了的小圖片
// 生成小圖片數(shù)量數(shù)組
getRandomData() {
// 隨機數(shù)集合
let randomArr = []
// 根據(jù)游戲等級生成最大值,減1是因為最大值保留作空白位放最后
let max = Math.pow(this.level, 2) - 1
while (randomArr.length < max) {
// 生成一個最大值范圍內(nèi)的隨機數(shù)
let random = Math.floor(Math.random() * max) + 1
if (randomArr.indexOf(random) == -1) {
// 沒有重復(fù)的就添加
randomArr.push(random)
}
}
randomArr.push(max + 1) // 添加最大數(shù)字作為最后的空白位
return randomArr // 如:[3, 1, 7, 2, 4, 8, 6, 5, 9]
}移動圖片
接收一個參數(shù),就是在遍歷隨機數(shù)數(shù)組 randomData 的時候,對應(yīng)每個圖片的值,鼠標(biāo)點擊的時候拿到這個值
// 移動圖片
move(idx: number) {
let level = this.level
let target = this.randomData.indexOf(idx) // 當(dāng)前點擊位置下標(biāo)
let space = this.randomData.indexOf(Math.pow(level, 2)) // 空白位置下標(biāo)
// 過濾一下,不然空白位置在最左邊時點擊右邊上一個數(shù)字時也能實現(xiàn)交換
// 以及空白位置在最右邊點擊左邊下一個數(shù)字時也能實現(xiàn)交換
let condition =
(space % level == 0 && target % level == level - 1) ||
(space % level == level - 1 && target % level == 0)
// 如果能交換
if (!condition) {
// 并且點擊目標(biāo)的,上或下或左或右是空白位,就交換位置
if (
target == space - level ||
target == space + level ||
target == space - 1 ||
target == space + 1
) {
this.change(space, target)
}
}
}
// 動起來
change(space: number, target: number) {
// 空白位置替換成目標(biāo)位置
this.randomData[space] = this.randomData[target]
// 目標(biāo)位置為最大值,實現(xiàn)交換
this.randomData[target] = Math.pow(this.level, 2)
// 步數(shù)
this.step += 1
// 檢查是否完成
this.finish()
}鍵盤事件
按下鍵盤上下左右的時候,判斷空格位置對應(yīng)你按的那個方向能不能移動,符合條件就替換
// 鍵盤事件
onKeydown(code: number) {
let level = this.level
// 目標(biāo)位置下標(biāo)
let target
// 空白位置下標(biāo)
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
}
}拼圖完成
思路是把當(dāng)前亂序的 randomData 轉(zhuǎn)為字符串,和正序的 finishData 作對比,如果一樣了,就是拼圖完成了
// 檢查是否拼圖完成
finish() {
// 如:'312' == '123'
if (this.randomData.join("") == this.finishData) {
ElMessageBox.alert(`恭喜你,闖關(guān)成功,僅用${this.step}步`, "提示", {
confirmButtonText: "OK",
callback: (action: Action) => {
this.randomData = []
this.step = 0
this.isStart = false
},
})
}
}
// 根據(jù)不同難度生成拼圖完成時的數(shù)據(jù)用來對比,判斷是否完成
// 比如初級難度就是:123456789
getFinishData(): string {
let str = ""
for (let i = 1, len = Math.pow(this.level, 2); i <= len; i++) {
str += i
}
return str
}結(jié)語
以上就是利用Vue.js制作一個拼圖華容道小游戲的詳細(xì)內(nèi)容,更多關(guān)于Vue.js拼圖華容道的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue 使用 Mint UI 實現(xiàn)左滑刪除效果CellSwipe
這篇文章主要介紹了Vue 使用 Mint UI 實現(xiàn)左滑刪除效果CellSwipe,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-04-04
建立和維護(hù)大型 Vue.js 項目的 10 個最佳實踐
這篇文章小編要與大家分享的是建立和維護(hù)大型 Vue.js 項目的 10 個最佳實踐,需要的小伙伴請和小編一起學(xué)習(xí)下面文章的具體內(nèi)容吧2021-09-09
Vue3組件不發(fā)生變化如何監(jiān)聽pinia中數(shù)據(jù)變化
這篇文章主要給大家介紹了關(guān)于Vue3組件不發(fā)生變化如何監(jiān)聽pinia中數(shù)據(jù)變化的相關(guān)資料,pinia是Vue的存儲庫,它允許您跨組件/頁面共享狀態(tài),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11
Vue filter 過濾當(dāng)前時間 實現(xiàn)實時更新效果
這篇文章主要介紹了Vue filter 過濾當(dāng)前時間 實現(xiàn)實時更新效果,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12
vue+koa2搭建mock數(shù)據(jù)環(huán)境的詳細(xì)教程
這篇文章主要介紹了vue+koa2搭建mock數(shù)據(jù)環(huán)境的方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05
vue3+vite+ts?通過svg-sprite-loader?插件使用自定義圖標(biāo)的詳細(xì)步驟
這篇文章主要介紹了vue3+vite+ts通過svg-sprite-loader插件使用自定義圖標(biāo),本文分步驟給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09

