周末閑來無事寫了一個JavaScript版掃雷游戲,現在把源代碼分享出來,共同學習。
掃雷游戲的原理大家可以參考這篇文章:http://www.cnblogs.com/goodwin/archive/2010/03/22/1691871.html
JavaScript代碼:
(function () { var FLM = function (id,rowCount,colCount, minLandMineCount, maxLandMineCount) { if (!(this instanceof FLM)) return new FLM(id, rowCount, colCount, minLandMineCount, maxLandMineCount); this.doc = document; this.table = this.doc.getElementById(id); this.cells = this.table.getElementsByTagName("td");//小格子 this.rowCount = rowCount || 10;//格子行數 this.colCount = colCount || 10;//格子列數 this.landMineCount = 0;//地雷個數 this.markLandMineCount = 0;//標記的地雷個數 this.minLandMineCount = minLandMineCount || 10;//地雷最少個數 this.maxLandMineCount = maxLandMineCount || 20;//地雷最多個數 this.arrs = [];//格子對應的數組 this.beginTime = null;//游戲開始時間 this.endTime = null;//游戲結束時間 this.currentSetpCount = 0;//當前走的步數 this.endCallBack = null;//游戲結束時的回調函數 this.landMineCallBack = null;//標記為地雷時更新剩余地雷個數的回調函數 this.doc.oncontextmenu = function () {//禁用右鍵菜單 return false; }; this.drawMap(); }; FLM.prototype = { //獲取元素 $: function (id) { return this.doc.getElementById(id); }, //畫地圖 drawMap: function () { var tds = []; for (var i = 0; i < this.rowCount; i++) { tds.push("<tr>"); for (var j = 0; j < this.colCount; j++) { tds.push("<td id='m" + i + "" + j + "'></td>"); } tds.push("</td>"); } this.table.innerHTML = tds.join(""); }, //初始化,一是設置數組默認值為0,二是確定地雷個數 init: function () { for (var i = 0; i < this.rowCount; i++) { this.arrs[i] = []; for (var j = 0; j < this.colCount; j++) { this.arrs[i][j] = 0; } } this.landMineCount = this.selectFrom(this.minLandMineCount, this.maxLandMineCount); }, //把是地雷的數組項的值設置為9 landMine: function () { var allCount = this.rowCount * this.colCount - 1, tempArr = {}; for (var i = 0; i < this.landMineCount; i++) { var randomNum = this.selectFrom(0, allCount), rowCol = this.getRowCol(randomNum); if (randomNum in tempArr) { i--; continue; } this.arrs[rowCol.row][rowCol.col] = 9; tempArr[randomNum] = randomNum; } }, //計算其他格子中的數字 calculateNoLandMineCount: function () { for (var i = 0; i < this.rowCount; i++) { for (var j = 0; j < this.colCount; j++) { if (this.arrs[i][j] == 9) continue; if (i > 0 && j > 0) { if (this.arrs[i - 1][j - 1] == 9) this.arrs[i][j]++; } if (i > 0) { if (this.arrs[i - 1][j] == 9) this.arrs[i][j]++; } if (i > 0 && j < this.colCount - 1) { if (this.arrs[i - 1][j + 1] == 9) this.arrs[i][j]++; } if (j > 0) { if (this.arrs[i][j - 1] == 9) this.arrs[i][j]++; } if (j < this.colCount - 1) { if (this.arrs[i][j + 1] == 9) this.arrs[i][j]++; } if (i < this.rowCount - 1 && j > 0) { if (this.arrs[i + 1][j - 1] == 9) this.arrs[i][j]++; } if (i < this.rowCount - 1) { if (this.arrs[i + 1][j] == 9) this.arrs[i][j]++; } if (i < this.rowCount - 1 && j < this.colCount - 1) { if (this.arrs[i + 1][j + 1] == 9) this.arrs[i][j]++; } } } }, //給每個格子綁定點擊事件(左鍵和右鍵) bindCells: function () { var self = this; for (var i = 0; i < this.rowCount; i++) { for (var j = 0; j < this.colCount; j++) { (function (row, col) { self.$("m" + i + "" + j).onmousedown = function (e) { e = e || window.event; var mouseNum = e.button; var className = this.className; if (mouseNum == 2) { if (className == "flag") { this.className = ""; self.markLandMineCount--; } else { this.className = "flag"; self.markLandMineCount++; } if (self.landMineCallBack) { self.landMineCallBack(self.landMineCount - self.markLandMineCount); } } else if (className != "flag") { self.openBlock.call(self, this, row, col); } }; })(i,j); } } }, //展開無雷區域 showNoLandMine: function (x, y) { for (var i = x - 1; i < x + 2; i++) for (var j = y - 1; j < y + 2; j++) { if (!(i == x && j == y)) { var ele = this.$("m" + i + "" + j); if (ele && ele.className == "") { this.openBlock.call(this, ele, i, j); } } } }, //顯示 openBlock: function (obj, x, y) { if (this.arrs[x][y] != 9) { this.currentSetpCount++; if (this.arrs[x][y] != 0) { obj.innerHTML = this.arrs[x][y]; } obj.style.backgroundColor = "green"; obj.className = "normal"; if (this.currentSetpCount + this.landMineCount == this.rowCount * this.colCount) { this.success(); } if (this.arrs[x][y] == 0) { this.showNoLandMine.call(this, x, y); } } else { this.failed(); } }, //顯示地雷 showLandMine: function () { for (var i = 0; i < this.rowCount; i++) { for (var j = 0; j < this.colCount; j++) { if (this.arrs[i][j] == 9) { this.$("m" + i.toString() + j).className = "landMine"; } } } }, //顯示所有格子信息 showAll: function () { for (var i = 0; i < this.rowCount; i++) { for (var j = 0; j < this.colCount; j++) { if (this.arrs[i][j] == 9) { this.$("m" + i.toString() + j).className = "landMine"; } else { if (this.arrs[i][j] != 0) this.$("m" + i.toString() + j).innerHTML = this.arrs[i][j]; } } } }, //清除顯示的格子信息 hideAll: function () { for (var i = 0; i < this.rowCount; i++) { for (var j = 0; j < this.colCount; j++) { var tdCell = this.$("m" + i.toString() + j); tdCell.className = ""; tdCell.innerHTML = ""; } } }, //刪除格子綁定的事件 disableAll: function () { for (var i = 0; i < this.rowCount; i++) { for (var j = 0; j < this.colCount; j++) { var tdCell = this.$("m" + i.toString() + j); tdCell.onmousedown = null; } } }, //游戲開始 begin: function () { this.currentSetpCount = 0;//開始的步數清零 this.markLandMineCount = 0; this.beginTime = new Date();//游戲開始時間 this.hideAll(); this.bindCells(); }, //游戲結束 end: function () { this.endTime = new Date();//游戲結束時間 if (this.endCallBack) {//如果有回調函數則調用 this.endCallBack(); } }, //游戲成功 success: function () { this.end(); this.showAll(); this.disableAll(); alert("Congratulation!"); }, //游戲失敗 failed: function () { this.end(); this.showAll(); this.disableAll(); alert("GAME OVER!"); }, //通數值找到行數和列數 getRowCol: function (val) { return { row: parseInt(val / this.colCount), col: val % this.colCount }; }, //獲取一個隨機數 selectFrom: function (iFirstValue, iLastValue) { var iChoices = iLastValue - iFirstValue + 1; return Math.floor(Math.random() * iChoices + iFirstValue); }, eventFire: function (el, etype) { if (el.fireEvent) { (el.fireEvent('on' + etype)); } else { var evObj = document.createEvent('Events'); evObj.initEvent(etype, false, false); el.dispatchEvent(evObj); } }, //入口函數 play: function () { this.init(); this.landMine(); this.calculateNoLandMineCount(); } }; window.FLM = FLM; })();
HTML部分:
<div id="FLM_main"> <table id="landmine"> </table> <div id="operation"> <div class="tip">剩余雷數:<span class="light red" id="landMineCount">0</span></div> <div class="tip">持續時間: <span class="light f60" id="costTime">0</span> s</div> <input type="button" id="showLandMine" value="顯示地雷" /><br /> <input type="button" id="showAll" value="顯示全部" /><br /> <input type="button" id="begin" value="開始游戲" /><br /> <div class="tip txtleft">提示: <ul> <li>1、點擊“開始游戲”游戲開始計時</li> <li>2、游戲過程中點擊“顯示地雷”或“顯示全部”游戲將會結束</li> </ul> </div> </div> </div>
調用部分:
window.onload = function () { var flm = FLM("landmine", 10, 10), doc = document, landMineCountElement = doc.getElementById("landMineCount"), timeShow = doc.getElementById("costTime"), showLandMineButton = doc.getElementById("showLandMine"), showAllButton = doc.getElementById("showAll"), beginButton = doc.getElementById("begin"), timeHandle = null; flm.endCallBack = function () { clearInterval(timeHandle); }; flm.landMineCallBack = function (count) { landMineCountElement.innerHTML = count; }; //為“開始游戲”按鈕綁定事件 beginButton.onclick = function () { flm.play();//初始化 //顯示地雷個數 landMineCountElement.innerHTML = flm.landMineCount; //為“顯示地址”按鈕綁定事件 showLandMineButton.onclick = function () { if (confirm("顯示地雷游戲將結束?")) { flm.failed(); flm.showLandMine(); } }; //為“顯示全部”按鈕綁定事件 showAllButton.onclick = function () { if (confirm("顯示全部游戲將結束?")) { flm.failed(); flm.showAll(); } }; //開始 flm.begin(); //更新花費時間 timeHandle = setInterval(function () { timeShow.innerHTML = parseInt((new Date() - flm.beginTime) / 1000); }, 1000); }; }
布局用的是table,所以FLM三個參數的第一個就是table的ID,第二個參數為最少地雷個數,第三個參數為最多地雷個數。
運行效果:
Demo |
剩余雷數:
0
持續時間:
0 s
提示:
- 1、點擊“開始游戲”游戲開始計時
- 2、游戲過程中點擊“顯示地雷”或“顯示全部”游戲將會結束
各位朋友們,果斷地把你們的成績截圖曬出來吧!!!