js版掃雷游戲
本文實(shí)例為大家分享了js版掃雷游戲的具體代碼,供大家參考,具體內(nèi)容如下
界面
考慮到簡單,一般,困難三個(gè)掃雷區(qū)域的格子數(shù)都不同,所以界面上的掃雷區(qū)域是用js動(dòng)態(tài)生成。
先搭好整體html框架:
<div class="container"> ?? ??? ?<div class="level"> ?? ??? ??? ?<button class="select">簡單</button> ?? ??? ??? ?<button>一般</button> ?? ??? ??? ?<button>困難</button> ?? ??? ??? ?<button>重新開始</button> ?? ??? ?</div> ?? ??? ?<div class="mine"> ?? ??? ??? ?//掃雷區(qū)域 ?? ??? ?</div> ?? ??? ?<div class="last">總共雷數(shù) : <span class="mineNum"></span></div> </div>
首先寫一個(gè)MineSweeper()構(gòu)造方法:
function MineSweeper(tr, td, mineNum) { ?? ?this.tr = tr; //行 ?? ?this.td = td; //列 ?? ?this.mineNum = mineNum; //雷數(shù) ?? ?this.area = []; ?//存取每個(gè)格子信息 ?? ?this.doms = []; ?//存儲(chǔ)格子DOM,用來動(dòng)態(tài)創(chuàng)建DOM ?? ?this.lastMineNum = mineNum; //剩余雷數(shù) ?? ?this.parent = document.querySelector('.mine'); ?? ?this.num = document.querySelector('.last .mineNum'); }
掃雷區(qū)域用一個(gè)二維數(shù)組表示并存儲(chǔ):
/* * 掃雷游戲區(qū)域area(二維數(shù)組) * [ * ? ? ?[type: mine/number, x1, y1], * ? ? ?[type: mine/number, x2, y2], * ? ? ? ... , * ? ? ?[type: mine/number, xn, yn] * ] */
其中type有兩個(gè)值,mine表示當(dāng)前格子是一個(gè)雷;number表示當(dāng)前格子是一個(gè)數(shù)字。
在構(gòu)造方法的原型上添加方法創(chuàng)建DOM表格,用來動(dòng)態(tài)生成掃雷區(qū)域界面:
MineSweeper.prototype.create = function() { ?? ?var _this = this; ?? ?var table = document.createElement('table'); ?? ?for(var i = 0; i < this.tr; i++) { ?? ??? ?var trDom = document.createElement('tr'); ?? ??? ?//創(chuàng)建行 ?? ??? ?this.doms[i] = []; ?? ??? ?for(var j = 0; j < this.td; j++) { ?? ??? ??? ?//創(chuàng)建列 ?? ??? ??? ?var tdDom = document.createElement('td'); ?? ??? ??? ?this.doms[i][j] = tdDom; ?? ??? ??? ?trDom.appendChild(tdDom); //往行中添加列 ?? ??? ?} ?? ??? ?table.appendChild(trDom);//往table中添加行 ?? ?} ?? ?this.parent.appendChild(table); //將table添加到界面 };
JS
function MineSweeper(tr, td, mineNum) { ?? ?this.tr = tr; //行 ?? ?this.td = td; //列 ?? ?this.mineNum = mineNum;? ?? ?this.area = [];? ?? ?this.doms = [];? ?? ?this.lastMineNum = mineNum;? ?? ?this.parent = document.querySelector('.mine'); ?? ?this.num = document.querySelector('.last .mineNum'); } //初始化 MineSweeper.prototype.init = function() { ?? ?var rn = this.randomNum(); //獲得type: mine 的索引 ?? ?var n = 0; //記錄格子索引 ?? ?for(var i = 0; i < this.tr; i++) { ?? ??? ?this.area[i] = []; ?? ??? ?for(var j = 0; j < this.td; j++) { ?? ??? ??? ?n ++; ?? ??? ??? ?if(rn.indexOf(n) !== -1) { ?? ??? ??? ??? ?this.area[i][j] = { ?? ??? ??? ??? ??? ?type: 'mine', ?? ??? ??? ??? ??? ?x: j, ?? ??? ??? ??? ??? ?y: i ?? ??? ??? ??? ?}; ?? ??? ??? ?} else { ?? ??? ??? ??? ?this.area[i][j] = { ?? ??? ??? ??? ??? ?type: 'number', ?? ??? ??? ??? ??? ?x: j, ?? ??? ??? ??? ??? ?y: i, ?? ??? ??? ??? ??? ?value: 0 ?? ??? ??? ??? ?}; ?? ??? ??? ?} ?? ??? ?} ?? ?} ?? ?// console.log(this.area); ?? ?this.num.innerHTML = this.mineNum; //初始化雷數(shù) ? ? this.parent.oncontextmenu = function() { ? ? ?? ?return false; //阻止右擊菜單事件 ? ? } ? ? this.updateNumber(); ?? ?//創(chuàng)建表格 ?? ?this.parent.innerHTML = ""; ?? ?this.create(); } //創(chuàng)建DOM表格 MineSweeper.prototype.create = function() { ?? ?var _this = this; ?? ?var table = document.createElement('table'); ?? ?for(var i = 0; i < this.tr; i++) { ?? ??? ?var trDom = document.createElement('tr'); ?? ??? ?this.doms[i] = []; ?? ??? ?for(var j = 0; j < this.td; j++) { ?? ??? ??? ?var tdDom = document.createElement('td'); ?? ??? ??? ?this.doms[i][j] = tdDom; ?? ??? ??? ?trDom.appendChild(tdDom); ? ? ? ? ? ? tdDom.pos = [i, j]; ?? ??? ??? ?tdDom.onmousedown = function(event) { ?? ??? ??? ??? ?if(event.button === 0) { ?//鼠標(biāo)左鍵 ?? ??? ??? ??? ??? ?var curArea = _this.area[this.pos[0]][this.pos[1]]; ?? ??? ??? ??? ??? ?console.log(curArea) ?? ??? ??? ??? ??? ?if(curArea.type === 'mine') { ?? ??? ??? ??? ??? ??? ?// console.log('踩到雷了!') ?? ??? ??? ??? ??? ??? ?this.className = 'mine'; ?? ??? ??? ??? ??? ??? ?_this.gameOver(this); ?? ??? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ??? ?// console.log('is number') ?? ??? ??? ??? ??? ??? ?if(!curArea.value) { ?//踩到0,出現(xiàn)一大片 ?? ??? ??? ??? ??? ??? ??? ?// console.log(0); ?? ??? ??? ??? ??? ??? ??? ?this.className = 'select'; //先顯示自己 ?? ??? ??? ??? ??? ??? ??? ?this.innerHTML = ''; ?? ??? ??? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ??? ??? ?function getAllZero(area) { ?? ??? ??? ??? ??? ??? ??? ??? ?var around = _this.mineAround(area); //找其周圍的格子 ?? ??? ??? ??? ??? ??? ??? ??? ?for(var i = 0; i < around.length; i++) { ?? ??? ??? ??? ??? ??? ??? ??? ??? ?var x = around[i][0]; //行 ?? ??? ??? ??? ??? ??? ??? ??? ??? ?var y = around[i][1]; //列 ?? ??? ??? ??? ??? ??? ??? ??? ??? ?_this.doms[x][y].className = 'select'; ?? ??? ??? ??? ??? ??? ??? ??? ??? ?if(!_this.area[x][y].value) { ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?if(!_this.doms[x][y].isHas) { ? ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?_this.doms[x][y].isHas = true; //標(biāo)記被找過的元素,避免格子重復(fù)重復(fù)被調(diào)用,導(dǎo)致內(nèi)存資源被濫用 ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?arguments.callee(_this.area[x][y]) ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?_this.doms[x][y].innerHTML = _this.area[x][y].value; ?? ??? ??? ??? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ??? ?getAllZero(curArea); ?? ??? ??? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ??? ??? ?this.className = 'select'; ?? ??? ??? ??? ??? ??? ??? ?this.innerHTML = curArea.value; ?? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ? ?? ??? ??? ??? ?} else if(event.button === 2) { ?//鼠標(biāo)右鍵 ?? ??? ??? ??? ??? ?this.className = this.className == 'flag'? '':'flag'; ?? ??? ??? ??? ??? ?//標(biāo)記小旗子,則剩余雷數(shù)-1 ?? ??? ??? ??? ??? ?if(this.className === 'flag') { ?? ??? ??? ??? ??? ??? ?_this.num.innerHTML = --_this.lastMineNum; ?? ??? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ??? ?_this.num.innerHTML = ++_this.lastMineNum; ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?} ?? ??? ?table.appendChild(trDom); ?? ?} ?? ?this.parent.appendChild(table); }; //生成指定數(shù)量的不重復(fù)的數(shù)字 MineSweeper.prototype.randomNum = function() { ?? ?var mineArr = new Array(this.tr*this.td); //該數(shù)組用來存儲(chǔ)所有格子下標(biāo) ?? ?for(var i = 0; i < mineArr.length; i++) { ?? ??? ?mineArr[i] = i; ?? ?} ?? ?mineArr.sort(function() {return 0.5 - Math.random()}); //將數(shù)組亂序排序 ?? ?return mineArr.slice(0, this.mineNum); //隨機(jī)取得放置雷的下標(biāo) }; //找目標(biāo)格子周圍的格子, 雷周圍的格子都需要number++ MineSweeper.prototype.mineAround = function(target) { ?? ?var x = target.x; ?? ?var y = target.y; ?? ?var result = []; //二位數(shù)組,存儲(chǔ)周圍格子的坐標(biāo) ?? ?for(var i = x-1; i <= x+1; i++) { ?? ??? ?for(var j = y-1; j <= y+1; j++) { ?? ??? ??? ?if( ? ? ? ? ? ? ? ? ? i < 0 || j < 0 || i > this.td - 1 || j > this.tr - 1 || ?//排除四個(gè)角 ? ? ? ? ? ? ? ? ? (i == x && j == y) || ? ? ? ? ? ? ? ? ? ? ? ? ? ?//排除周圍是雷 ? ? ? ? ? ? ? ? ? this.area[j][i].type === 'mine' ? ? ?? ??? ??? ? ?){ ?? ??? ??? ??? ?continue; ?? ??? ??? ?} ?? ??? ??? ?result.push([j, i]); ?? ??? ?} ?? ?} ?? ?return result;? }; //更新所有數(shù)字 MineSweeper.prototype.updateNumber = function() { ?? ?for(var i = 0; i < this.tr; i++) { ?? ??? ?for(var j = 0; j < this.td; j++) { ?? ??? ??? ?if(this.area[i][j].type == 'number') { ?? ??? ??? ??? ?continue; ?? ??? ??? ?} ?? ??? ??? ?var nums = this.mineAround(this.area[i][j]); ?//獲取雷周圍的格子 ?? ??? ??? ?for(var k = 0; k < nums.length; k++) { ?? ??? ??? ??? ?//雷周圍的格子的number都要+1 ?? ??? ??? ??? ?this.area[nums[k][0]][nums[k][1]].value += 1; ?? ??? ??? ?} ?? ??? ?} ?? ?} }; //gameOver MineSweeper.prototype.gameOver = function(downMine) { ?? ?for(var i = 0; i < this.tr; i++) { ?? ??? ?for(var j = 0; j < this.td; j++) { ?? ??? ??? ?if(this.area[i][j].type === 'mine') { ?? ??? ??? ??? ?this.doms[i][j].className = 'mine'; ?? ??? ??? ?} ?? ??? ??? ?this.doms[i][j].onmousedown = null; ?? ??? ?} ?? ?} ?? ?if(downMine) { ?? ??? ?downMine.style.backgroundColor = '#f40'; ?? ?} } function startGame() { ?? ?var btn = document.querySelectorAll('.container .level>button'); ?? ?var arr = [[10,10,15],[15,15,40],[20,20,80]]; ?? ?var select = 0; //當(dāng)前選中狀態(tài)的按鈕 ?? ?var mine = null; ?? ?for(let i = 0; i < btn.length - 1; i++) { ?? ??? ?console.log(i); ?? ??? ?console.log(arr); ?? ??? ?btn[i].onclick = function(e) { ?? ??? ??? ?btn[select].className = ''; ?? ??? ??? ?this.className = 'select'; ?? ??? ??? ?select = i; ?? ??? ??? ?mine = new MineSweeper(...arr[i]); ?? ??? ??? ?console.log(arr[i]); ?? ??? ??? ?mine.init(); ?? ??? ?} ?? ?} ?? ?btn[0].onclick(); ?? ?btn[3].onclick = function() { ?? ??? ?mine.init(); ?? ?} } startGame();
CSS
.container { ?? ?margin: 30px auto; ?? ?text-align: center; } .container .level button { ?? ?background-color: #e5c1cd; ?? ?outline-style: none; ?? ?border: none; ?? ?cursor: pointer; ?? ?color: #fff; } .container .level button.select { ?? ?background-color: #b6b4c2; } .container .mine table { ?? ?border-spacing: 1px; ?? ?margin: 10px auto; } .container .mine table td { ?? ?width: 18px; ?? ?height: 18px; ?? ?padding: 0; ?? ?background-color: #bfb8da; ?? ?border: 2px solid; ?? ?border-color: #ebd7d4 #a56781 #a56781 #ebd7d4; ?? ?text-align: center; ?? ?line-height: 16px; ?? ?font-weight: bold; } .container .mine table td.select, .container .mine table td.mine { ?? ?background-color: #bfb8da; ?? ?border: 1px solid #ebd7d4; } .container .mine table td.mine { ?? ?background-image: url("../image/mine.png"); ?? ?background-repeat: no-repeat; ?? ?background-size: cover; } .container .mine table td.flag { ?? ?background-image: url("../image/flag.png"); ?? ?background-repeat: no-repeat; ?? ?background-size: cover; } .container .last { ?? ?color: #d87f81; }
HTML
<!DOCTYPE html> <html lang="en"> <head> ?? ?<meta charset="UTF-8"> ?? ?<title>MineSweeper</title> ?? ?<link rel="stylesheet" href="./css/index.css"> </head> <body> ?? ?<div class="container"> ?? ??? ?<div class="level"> ?? ??? ??? ?<button class="select">簡單</button> ?? ??? ??? ?<button>一般</button> ?? ??? ??? ?<button>困難</button> ?? ??? ??? ?<button>重新開始</button> ?? ??? ?</div> ?? ??? ?<div class="mine"> ?? ??? ??? ? ?? ??? ?</div> ?? ??? ?<div class="last">總共雷數(shù) : <span class="mineNum"></span></div> ?? ?</div> <script src="./js/index.js"></script> </body> </html>
更新數(shù)字
遍歷掃雷區(qū)域數(shù)組,當(dāng)遇到雷時(shí),取到其周圍的格子,如果是數(shù)字,則number都+1;如果是雷,則該格子不作操作。
MineSweeper.prototype.updateNumber = function() { ?? ?for(var i = 0; i < this.tr; i++) { ?? ??? ?for(var j = 0; j < this.td; j++) { ?? ??? ??? ?if(this.area[i][j].type == 'number') { ?? ??? ??? ??? ?continue; ?//遇到數(shù)字格子跳過,不需要取其周圍的格子 ?? ??? ??? ?} ?? ??? ??? ?var nums = this.mineAround(this.area[i][j]); ?//獲取雷周圍的格子 ?? ??? ??? ?for(var k = 0; k < nums.length; k++) { ?? ??? ??? ??? ?//雷周圍的格子的number都要+1 ?? ??? ??? ??? ?this.area[nums[k][0]][nums[k][1]].value += 1; ?? ??? ??? ?} ?? ??? ?} ?? ?} };
實(shí)現(xiàn)效果:
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript Array Flatten 與遞歸使用介紹
用 JavaScript 將 [1,2,3,[4,5, [6,7]], [[[8]]]] 這樣一個(gè) Array 變成 [1,2,3,4,5, 6,7,8] 呢?傳說中的 Array Flatten2011-10-10js實(shí)現(xiàn)點(diǎn)擊左右按鈕輪播圖片效果實(shí)例
這篇文章主要介紹了js實(shí)現(xiàn)點(diǎn)擊左右按鈕輪播圖片效果的方法,涉及click事件相應(yīng)、animate方法等使用技巧,需要的朋友可以參考下2015-01-01使用typescript類型實(shí)現(xiàn)ThreeSum
這篇文章主要介紹了使用typescript類型實(shí)現(xiàn)ThreeSum,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以一下,希望對(duì)你學(xué)習(xí)又是幫助2022-08-08