<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
佈局就是經典的方格佈局,對於場景的美觀度可以自行找幾個配色網站作為參考。
出現問題: 先初始化一個二維陣列對應方塊座標,然後依次渲染 or
直接通過預期的行、列數渲染空白方塊
區別: 直接初始化二維陣列,可以對座標進行一些屬性操作,例如標記、是否為地雷等等,之後操作的時候會方便很多,缺點在初始化的時候需要進行大量的計算工作(因為在點開一個安全座標時需要顯示周圍的地雷個數,還要考慮邊緣情況),而渲染空白方塊就可以在點選座標的時候再去做計算,並且在點選的時候只需要計算該方塊的屬性。
這裡我選擇了渲染空白方塊的形式。
程式碼實現
使用了 element-ui元件
template
<div class="layout"> <div class="row" v-for="row in layoutConfig.row" :key="row"> <div class="cell" :style="{ width: edgeLength, height: edgeLength }" v-for="col in layoutConfig.cell" :key="col"> <div class="block" @click="open(row, col, $event)" @contextmenu.prevent="sign(row, col, $event)" > // 這裡的邏輯現在可以暫時不用管,只需要先做好佈局 <template v-if="areaSign[`${row}-${col}`] === 'fail'"> <img src="../../assets/svg/fail.svg" alt=""> </template> <template v-else-if="areaSign[`${row}-${col}`] === 'tag'"> <img src="../../assets/svg/Flag.svg" alt=""> </template> <template v-else-if="areaSign[`${row}-${col}`] === 'normal'"> </template> <template v-else> {{areaSign[`${row}-${col}`]}} </template> </div> </div> </div> </div>
style:
<style scoped lang="less"> .container { display: flex; justify-content: center; align-items: center; flex-direction: column; margin-top: 100px; .typeChoose { display: flex; justify-content: center; align-items: center; width: 100%; margin-bottom: 20px; .item { margin: 0 10px; } } .layout { width: 500px; height: 500px; .row { display: flex; justify-content: center; align-items: center; .cell { border: 1px solid #735E30; caret-color: transparent; cursor: pointer; line-height: 50px; .block { height: 100%; background: #292E17; } .block:hover { background: #96875F; } .opened { height: 100%; background: #E8E0D8; } } } } } </style>
生成地雷隨機二維陣列
因為佈局已經通過空白方塊生成了,所以我們只需要關心生成隨機的地雷座標就可以了
程式碼實現:
/* * type: 當前模式的地雷個數(自己定義數量) * mineList: 地雷座標陣列 * layoutConfig: { * row: 佈局的行數 * col: 佈局的列數 * } */ // 生成隨機地雷座標陣列 initMineListRange () { while (this.mineList.length < this.type) { this.initMineItem() } }, // 生成單個地雷座標並且放入地雷座標陣列(mineList)中 initMineItem () { const position = this.initPositionRange([1, this.layoutConfig.row], [1, this.layoutConfig.cell]) if (!this.hasPositionIn(position, this.mineList)) { this.mineList.push(position) } }, // 生成一個在給定範圍內的隨機座標 initPositionRange ([xStart, xEnd], [yStart, yEnd]) { return [this.numRange(xStart, xEnd), this.numRange(yStart, yEnd)] }, // 生成一個在給定範圍內的隨機整數 numRange (start, end) { return Math.floor((Math.random() * (end - start + 1))) + start }, // 判斷引數中的 position 是否已經存在與 引數中的 positionList 中 hasPositionIn (position, positionList) { console.assert(position.length === 2, 'position length < 2, not a position item') return positionList.some(p => { return p[0] === position[0] && p[1] === position[1] }) }
指的是遊戲中的一些操作以及某個操作導致的一系列變化
點選方塊
分析:點選方塊之後會出現三種情況
對應這三種情況需要分別有不同的表現形式
第一種情況:(方塊的九宮格範圍內沒有地雷)
這種情況只需要將該方塊的樣式改為點選過的樣式即可(class="opened"
)
第二種情況:(方塊的九宮格方位內有地雷)
修改樣式為opened
,並且需要計算周圍的地雷數量(需要考慮邊緣情況,即當前座標是否在邊緣)
第三種情況:(踩雷)
修改樣式為opened
, 並且展示地雷,提示使用者遊戲結束
程式碼實現
因為在點選之前該方塊是空白物件,所以需要一個物件來儲存該方塊的屬性或者狀態(areaSign
)
/* * areaSign: Object key: 座標('1-2') value: 狀態 * gameProcess:當前遊戲是否處於進行狀態 * statusEnum: 列舉 方塊狀態列舉值(fail,normal,tag) */ // 方塊點選事件 (傳入座標以及點選事件物件) open (rowIndex, colIndex, e) { // 判斷當前遊戲是否 if (!this.gameProcess) { this.gameEndConfirm() return } // 判斷當前座標是否被標記,被標記則不能被點開 if (this.getAreaSignValueWithPosition(rowIndex, colIndex) === statusEnum.tag) { this.confirmMessageBox('該區域已經被標記,請選擇其他區域點選') return } e.target.className = 'opened' if (this.hasTouchMine([rowIndex, colIndex])) { // 踩雷 this.mineTouched([rowIndex, colIndex]) } else { // 第一、二種情況 this.safeTouched([rowIndex, colIndex]) } }, // 通過傳入的座標判斷是否存在地雷座標陣列中 hasTouchMine ([xPosition, yPosition]) { return this.hasPositionIn([xPosition, yPosition], this.mineList) }, mineTouched (position) { this.setSvg(position, statusEnum.fail) // 遊戲失敗提示 this.gameProcess = false this.gameEndConfirm() }, safeTouched (position) { this.setTips(position) }, // 把傳入座標通過判斷是否有雷設定對應提示 setTips (position) { const total = this.positionAroundMineTotal(position) this.$set(this.areaSign, `${position[0]}-${position[1]}`, total || '') }, // 把傳入座標設定為對應狀態的svg圖示 setSvg (position, type) { this.$set(this.areaSign, `${position[0]}-${position[1]}`, type) }, // 傳入座標與地雷座標陣列判斷是否其周圍存在雷 positionAroundMineTotal (position) { const aroundPositionList = this.getAroundPosition(position[0], position[1]) return aroundPositionList.filter(item => this.hasTouchMine(item)).length }, // 獲取傳入座標的周圍九宮格座標 getAroundPosition (xPosition, yPosition) { const aroundPositionList = [ [xPosition - 1, yPosition - 1], [xPosition - 1, yPosition], [xPosition - 1, yPosition + 1], [xPosition, yPosition - 1], [xPosition, yPosition + 1], [xPosition + 1, yPosition - 1], [xPosition + 1, yPosition], [xPosition + 1, yPosition + 1] ] return aroundPositionList.filter(position => isInRange(position[0]) && isInRange(position[1])) // 判斷傳入數位是否在對應範圍中 function isInRange (num, range = [1, 10]) { return num >= range[0] && num <= range[1] } }
標記座標
左鍵為點選方塊,右鍵為標記座標(第二次點選為取消標記),當該座標為標記的時候,無法進行點選,並且當剛好標記的座標陣列和地雷陣列一樣時,則遊戲結束,玩家勝利
程式碼實現
/* * hasWin 見下文的 vue computed */ sign (rowIndex, colIndex, e) { // 判斷遊戲當前狀態 if (!this.gameProcess) { this.gameEndConfirm() return } if (this.getAreaSignValueWithPosition(rowIndex, colIndex) === undefined || this.getAreaSignValueWithPosition(rowIndex, colIndex) === statusEnum.normal) { // 當前座標 為被標記過或者以及被取消標記 觸發:新增標記 this.setSvg([rowIndex, colIndex], statusEnum.tag) } else if (this.getAreaSignValueWithPosition(rowIndex, colIndex) === statusEnum.tag) { // 當前座標 被標記 觸發:取消標記 this.setSvg([rowIndex, colIndex], statusEnum.normal) } console.log(this.tagList, this.mineList) // 檢測遊戲是否結束 this.gameInspector() }, // 遊戲提示 gameEndConfirm () { const message = this.hasWin ? '恭喜你通關,是否繼續?' : '遊戲失敗,是否重新開始?' this.confirmMessageBox(message, { callback: () => { this.resetGame() }, cancelCallback: () => {} }, 'confirm') }, // 遊戲狀態檢測員(判斷當前遊戲是否結束) gameInspector () { if (this.hasWin) { this.gameEndConfirm() } }, // 通過傳入座標返回對應格式的字串(areaSign的key值) getAreaSignAttrWithPosition (xPosition, yPosition) { return `${xPosition}-${yPosition}` }, // 通過傳入座標返回areaSign的value值(獲取該座標的狀態) getAreaSignValueWithPosition (xPosition, yPosition) { return this.areaSign[this.getAreaSignAttrWithPosition(xPosition, yPosition)] }
// 被標記列表 tagList () { return Object.keys(this.areaSign) .filter(item => this.areaSign[item] === 'tag') .map(attrStr => attrStr.split('-').map(str => parseInt(str))) }, // 判斷所有的地雷是否已經被標記 hasSignAllMine () { return this.tagList.length === this.mineList.length && this.tagList.every(tagPosition => this.hasPositionIn(tagPosition, this.mineList)) }, // 遊戲是否勝利 hasWin () { return this.hasSignAllMine }
遊戲失敗或者勝利的時候需要重置遊戲
程式碼實現
resetGame () { this.gameProcess = true this.areaSign = {} this.mineList = [] this.resetOpenedClass() // 初始化遊戲 this.initMineListRange() }, // 將class = "opened" 的元素改回 "block" 狀態 resetOpenedClass () { document.querySelectorAll('.opened').forEach(node => { node.className = 'block' }) }
掃雷的實現並不複雜,首先需要對掃雷這個遊戲的機制有思路,並且可以將一些邏輯捋清楚就可以了,實現的時候再將一些邊緣狀態考慮一下。可以更多關注一下對於程式碼的封裝,對於程式碼的提煉很重要,這樣在之後繼續開發或者需要修改的時候很容易上手。
以上就是Vue2+JS實現掃雷小遊戲的詳細內容,更多關於Vue掃雷遊戲的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45