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