js版掃雷游戲
本文實例為大家分享了js版掃雷游戲的具體代碼,供大家參考,具體內容如下
界面
考慮到簡單,一般,困難三個掃雷區(qū)域的格子數都不同,所以界面上的掃雷區(qū)域是用js動態(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">總共雷數 : <span class="mineNum"></span></div> </div>
首先寫一個MineSweeper()構造方法:
function MineSweeper(tr, td, mineNum) { ?? ?this.tr = tr; //行 ?? ?this.td = td; //列 ?? ?this.mineNum = mineNum; //雷數 ?? ?this.area = []; ?//存取每個格子信息 ?? ?this.doms = []; ?//存儲格子DOM,用來動態(tài)創(chuàng)建DOM ?? ?this.lastMineNum = mineNum; //剩余雷數 ?? ?this.parent = document.querySelector('.mine'); ?? ?this.num = document.querySelector('.last .mineNum'); }
掃雷區(qū)域用一個二維數組表示并存儲:
/* * 掃雷游戲區(qū)域area(二維數組) * [ * ? ? ?[type: mine/number, x1, y1], * ? ? ?[type: mine/number, x2, y2], * ? ? ? ... , * ? ? ?[type: mine/number, xn, yn] * ] */
其中type有兩個值,mine表示當前格子是一個雷;number表示當前格子是一個數字。
在構造方法的原型上添加方法創(chuàng)建DOM表格,用來動態(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; //初始化雷數 ? ? 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) { ?//鼠標左鍵 ?? ??? ??? ??? ??? ?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,出現一大片 ?? ??? ??? ??? ??? ??? ??? ?// 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; //標記被找過的元素,避免格子重復重復被調用,導致內存資源被濫用 ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?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) { ?//鼠標右鍵 ?? ??? ??? ??? ??? ?this.className = this.className == 'flag'? '':'flag'; ?? ??? ??? ??? ??? ?//標記小旗子,則剩余雷數-1 ?? ??? ??? ??? ??? ?if(this.className === 'flag') { ?? ??? ??? ??? ??? ??? ?_this.num.innerHTML = --_this.lastMineNum; ?? ??? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ??? ?_this.num.innerHTML = ++_this.lastMineNum; ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?} ?? ??? ?table.appendChild(trDom); ?? ?} ?? ?this.parent.appendChild(table); }; //生成指定數量的不重復的數字 MineSweeper.prototype.randomNum = function() { ?? ?var mineArr = new Array(this.tr*this.td); //該數組用來存儲所有格子下標 ?? ?for(var i = 0; i < mineArr.length; i++) { ?? ??? ?mineArr[i] = i; ?? ?} ?? ?mineArr.sort(function() {return 0.5 - Math.random()}); //將數組亂序排序 ?? ?return mineArr.slice(0, this.mineNum); //隨機取得放置雷的下標 }; //找目標格子周圍的格子, 雷周圍的格子都需要number++ MineSweeper.prototype.mineAround = function(target) { ?? ?var x = target.x; ?? ?var y = target.y; ?? ?var result = []; //二位數組,存儲周圍格子的坐標 ?? ?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 || ?//排除四個角 ? ? ? ? ? ? ? ? ? (i == x && j == y) || ? ? ? ? ? ? ? ? ? ? ? ? ? ?//排除周圍是雷 ? ? ? ? ? ? ? ? ? this.area[j][i].type === 'mine' ? ? ?? ??? ??? ? ?){ ?? ??? ??? ??? ?continue; ?? ??? ??? ?} ?? ??? ??? ?result.push([j, i]); ?? ??? ?} ?? ?} ?? ?return result;? }; //更新所有數字 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; //當前選中狀態(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">總共雷數 : <span class="mineNum"></span></div> ?? ?</div> <script src="./js/index.js"></script> </body> </html>
更新數字
遍歷掃雷區(qū)域數組,當遇到雷時,取到其周圍的格子,如果是數字,則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; ?//遇到數字格子跳過,不需要取其周圍的格子 ?? ??? ??? ?} ?? ??? ??? ?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; ?? ??? ??? ?} ?? ??? ?} ?? ?} };
實現效果:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
JavaScript Array Flatten 與遞歸使用介紹
用 JavaScript 將 [1,2,3,[4,5, [6,7]], [[[8]]]] 這樣一個 Array 變成 [1,2,3,4,5, 6,7,8] 呢?傳說中的 Array Flatten2011-10-10