基于Vue3實(shí)現(xiàn)數(shù)字華容道游戲的示例代碼
前言
恰逢春之四月,天氣忽熱忽涼,遇游戲大賽,以笨拙之技,書(shū)一篇小文。
游戲規(guī)則:存在n*n的格子,需要將它們按數(shù)字順序或圖片順序一一還原即可。
環(huán)境
主要環(huán)境:
vue3 version:3.2.4
vite version:2.5.0
vue-router version:4.0.14
注:這個(gè)游戲的路由使用的是自動(dòng)路由插件
主要插件:
windicss version:3.5.1
運(yùn)行如圖:
思路
- 搭建環(huán)境,下載依賴
- 運(yùn)行項(xiàng)目
- 利用windicss主體兼容pc和移動(dòng)端
姑且認(rèn)為小于1024的是平板或者手機(jī) lg(1024px)
App.vue
<div class="relative w-full h-full lg:(w-750px h-800px)"> <route-view </div>
主體Game.vue設(shè)置4個(gè)主體組件:GameTool.vue游戲工具欄(返回、開(kāi)始和步數(shù)統(tǒng)計(jì))、GameCnt.vue游戲主體、Tip.vue開(kāi)局提示、GamePass.vue游戲通過(guò)
實(shí)現(xiàn)
GameCnt
布局
- 先畫(huà)出3*3的格子,這里有多種方法,筆者這里采取最簡(jiǎn)單的動(dòng)態(tài)grid布局實(shí)現(xiàn),后來(lái)因?yàn)閏ss動(dòng)畫(huà)選取的是transform則不用gird布局了
- 寬高獲取,這里要獲取,原因是使用了transform位移動(dòng)畫(huà),則需要平移距離和寬高了
- 設(shè)置lazyShow,讓第一次渲染不會(huì)有transform動(dòng)畫(huà)
- 隱藏最后一個(gè),利用數(shù)組對(duì)象value值+css實(shí)現(xiàn)
- 添加其他css(windicss不好實(shí)現(xiàn)的css)
// 定義行個(gè)數(shù) const rowLen = 3 // 定義cnt寬高和item的寬高 const cntWidth = ref(0) const cntHeight = ref(0) const itemWidth = ref(0) const itemHeight = ref(0) // 定義數(shù)組 const lists = ref([]) lists.value = new Array(rowLen.value * rowLen.value).fill(1).map((item, index) => ({ key: index, // 存儲(chǔ)原序號(hào) value: item, // 1 代表不是空位 moveIndex: index })) // 設(shè)置最后一個(gè)為-1 lists.value[lists.value.length - 1]['value'] = 0 //獲取dom和渲染 onMounted(() => { // 獲取cnt寬高和item的寬高 getCntWidth() // 讓第一次渲染不會(huì)有transform動(dòng)畫(huà) lazyShow.value = false })
<div v-show="!lazyShow" v-for="(item, index ) in lists" class="box rounded-md overflow-hidden absolute" :class="[item.value ? 'origin' : 'opacity-0']" @click="boxClick(item)" :style="{ transform: `translate(${(item.moveIndex % rowLen) * (1 / rowLen) * cntWidth}px, ${parseInt(item.moveIndex / rowLen) * (1 / rowLen) * cntHeight}px) `, width: itemWidth + 'px', height: itemHeight + 'px' }"> <p class="absolute z-10 text-light-100 left-1/2 top-1/2" :class="hasImg ? 'opacity-60' : ''" :style="{ 'font-size': (180 / rowLen) + 'px' }">{{ item.key + 1 }}</p> </div>
點(diǎn)擊元素的交換
核心代碼:
// 是否在一行 const isInline = parseInt(index / rowLen.value) === parseInt(emptyIndex / rowLen.value) // 在一行是否相鄰 Math.abs(emptyIndex - index) === 1 // 不在一行是否是上下關(guān)系 Math.abs(index - emptyIndex) === rowLen.value
點(diǎn)擊元素上下左右的交換
先判斷是否在一行,再判斷是否相鄰即可。
- 先判斷是否在一行
- 在一行是否相鄰或不在一行是否是上下關(guān)系
- 看情況調(diào)用changeIndex
// 是否在一行 if (isInline) { // 一行則判斷是否左右相鄰 console.log('相差:' + (index - emptyIndex)) // 是否相鄰 if (Math.abs(emptyIndex - index) === 1) { // 改變對(duì)應(yīng)moveIndex changeIndex() } else { console.log('不相鄰') return } } else { // 不是則判斷是否上下相鄰 console.log('相差:' + (index - emptyIndex)) // 是否上或者下 if (Math.abs(index - emptyIndex) === rowLen.value) { // 改變對(duì)應(yīng)moveIndex changeIndex() } else { console.log('不相鄰') return } } // 聲明改變的數(shù)組moveIndex的方法 const changeIndex = () => { // 步數(shù)改變 emit('stepChange'); // 改變對(duì)應(yīng)數(shù)組里的moveIndex 注意不是 index和 moveIndex ([lists.value[item.key].moveIndex, lists.value[emptyItem.key].moveIndex] = [emptyIndex, index]); }
判斷游戲通過(guò)
這個(gè)地方很簡(jiǎn)單,主要判斷數(shù)組對(duì)象每一個(gè)是否原序號(hào)key是否都相等于移動(dòng)后的moveIndex
// 是否都成功 const getIsAllOk = () => { // return lists.value.some(item => item.moveIndex !== item.key) } // // 判斷是否都成功了 const flag = getIsAllOk() console.log(flag) if (!flag) { // alert('成功') gamePass() }
注:這個(gè)gamePass
需要在defineEmits里注冊(cè)
打亂數(shù)組
這個(gè)地方很有點(diǎn)麻煩,存在無(wú)解的情況,暫時(shí)沒(méi)想到更好的實(shí)現(xiàn)方法,這里使用的是排序打亂
// 打亂數(shù)據(jù) const mixData = () => { const arr = new Array(rowLen.value * rowLen.value).fill(0).map((item, index) => index) // console.log(arr) arr.sort(() => { return Math.random() > 0.5 ? -1 : 1 }) arr.forEach((item, index) => { lists.value[index].moveIndex = item }) // 如果直接是成功的則重新來(lái)一次排序 const flag = getIsAllOk() if (!flag) { // alert('成功') mixData() } }
注:有想法可以溝通下,一起提升!
動(dòng)態(tài)格子和寬高
const params = route.query // 定義行個(gè)數(shù) rowLen.value = +params.num || 3; // 重新獲取item寬高 cnt.value && getCntWidth()
圖片華容道
圖片使用定位。然后超出截取即可展示出效果
<img v-if="hasImg" class="absolute" :src="Default" alt="" :style="{ width: cntWidth + 'px', maxWidth: cntWidth + 'px', height: cntHeight + 'px', left: -(item.key % rowLen) * (1 / rowLen) * cntWidth + 'px', top: -parseInt(item.key / rowLen) * (1 / rowLen) * cntHeight + 'px' }"> // 是否渲染圖片 hasImg.value = params.hasImg === '1' ? true : false;
GameTool
左側(cè)是返回按鈕,右側(cè)是重新開(kāi)始按鈕,中間是移動(dòng)步數(shù)
移動(dòng)步數(shù)后中間會(huì)調(diào)整為移動(dòng)多少次
注:圖標(biāo)從iconfont找的
GamePass
- 先布局全屏遮罩
- 設(shè)置中間div樣式
- 設(shè)置通過(guò)成功提示和步數(shù)提示即可
GameTip
這個(gè)組件就是開(kāi)局的提示組件
Menu
這個(gè)組件就是菜單頁(yè) 設(shè)置了兩種入口
最后
GameCnt 可以寫(xiě)一些測(cè)試代碼,方便測(cè)試下通關(guān)后的情況
GameCnt 的塊級(jí)效果優(yōu)化過(guò),否則只有顏色,不太好看
GamePass 還有優(yōu)化空間,例如圖片通過(guò)可以有不同效果啊等等
整體難度不高,可以練習(xí)下vue3,以及游戲思維
到此這篇關(guān)于基于Vue3實(shí)現(xiàn)數(shù)字華容道游戲的示例代碼的文章就介紹到這了,更多相關(guān)Vue數(shù)字華容道內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vscode中vue-cli項(xiàng)目es-lint的配置方法
本文主要介紹vscode中 vue項(xiàng)目es-lint的配置方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的的朋友參考下吧2018-07-07vue中$nexttick,$set,$forceupdate的區(qū)別
本文主要介紹了vue中$nexttick,$set,$forceupdate的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07前端Vue項(xiàng)目部署到服務(wù)器的全過(guò)程以及踩坑記錄
使用Vue做前后端分離項(xiàng)目時(shí),通常前端是單獨(dú)部署,用戶訪問(wèn)的也是前端項(xiàng)目地址,因此前端開(kāi)發(fā)人員很有必要熟悉一下項(xiàng)目部署的流程,下面這篇文章主要給大家介紹了關(guān)于前端Vue項(xiàng)目部署到服務(wù)器的全過(guò)程以及踩坑記錄的相關(guān)資料,需要的朋友可以參考下2023-05-05Django與Vue語(yǔ)法的沖突問(wèn)題完美解決方法
這篇文章主要介紹了Django與Vue語(yǔ)法的沖突問(wèn)題完美解決方法,本文給大家分享了兩種解決方法,需要的朋友參考下吧2017-12-12vue項(xiàng)目中created()被調(diào)用多次的踩坑實(shí)戰(zhàn)
在vue項(xiàng)目中我在created中調(diào)用了兩次get數(shù)據(jù)請(qǐng)求,所以下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目中created()被調(diào)用多次的踩坑實(shí)戰(zhàn),需要的朋友可以參考下2023-03-03vue中手機(jī)號(hào),郵箱正則驗(yàn)證以及60s發(fā)送驗(yàn)證碼的實(shí)例
下面小編就為大家分享一篇vue中手機(jī)號(hào),郵箱正則驗(yàn)證以及60s發(fā)送驗(yàn)證碼的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03vue動(dòng)態(tài)組件之:is在組件中的使用場(chǎng)景
這篇文章主要介紹了vue動(dòng)態(tài)組件之:is在組件中的使用場(chǎng)景,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07