生活随笔
收集整理的這篇文章主要介紹了
网页版扫雷小游戏
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
掃雷小游戲(原生js)
實驗介紹
實驗簡介
先上一張效果圖
源代碼獲取(非本文章中代碼)
$ git clone https://github.com/shiyanlou/js-minesweeper
學習網(wǎng)頁
實驗樓-網(wǎng)頁版掃雷
實現(xiàn)原理
掃雷游戲的規(guī)則:
游戲面板上有一些格子,每個格子中有一個數(shù)字(空白表示數(shù)字為 0)或是地雷,格子中的數(shù)字表示格子周圍格子中地雷的數(shù)量。玩家要做的就是把數(shù)字格子找出來,時間花的越少越好。
除邊界上的格子外,每個格子周圍有 8 個格子:上、下、左、右、4 個斜角。所以數(shù)字范圍是 0~8。
所以我們的算法如下:
根據(jù)用戶選擇的難易程度(有初、中、高三個級別,級別越高地雷和格子數(shù)量越多),隨機產(chǎn)生一定個數(shù)的地雷并隨機放在格子中。然后遍歷格子,計算每個格子中的數(shù)字,標記在格子上。玩家左鍵點擊格子時顯示格子內(nèi)容(如果遇到地雷則挑戰(zhàn)失敗,游戲結(jié)束),右鍵點擊格子時標記格子為地雷,真到正確標記所有地雷并打開所有非地雷格子,挑戰(zhàn)成功,游戲結(jié)束。
目錄結(jié)構(gòu):
實驗步驟
頁面布局
<body>
<div id="box"><table id="game"></table><div id="control"><div id="restMine">剩余雷數(shù): <span id="restMineCount" style="font-size: 18px;color: red;"> 0 </span>個</div><div id="useTime">持續(xù)時間: <span id="useTimeSecond" style="font-size: 18px;color: red;"> 0 </span>秒</div><form><fieldset><legend>難度選擇:</legend><input type="radio" name="difficultLevel" id="hard1" checked/><label for="hard1"> 初級(10*10)</label><br><input type="radio" name="difficultLevel" id="hard2"/><label for="hard2"> 中級(15*15)</label><br><input type="radio" name="difficultLevel" id="hard3"/><label for="hard3"> 高級(20*20)</label><br></fieldset></form><button id="startGame">開始新游戲</button><div id="info"><h5>提示:</h5><ul><li>點擊“開始新游戲”開始計時</li><li>游戲過程中點擊“開始新游戲”則重新開始</li></ul></div></div>
</div>
css布局
*{padding:0px;margin: 0px;
}#box{width: auto;height: auto;float: left;border: 1px solid indianred;margin: 100px auto;
}#game{float: left;background:#CCC;
}#game td{width: 32px;height:32px;border:2px outset #EEE;text-align:center;cursor:pointer;font-size: 25px;line-height: 32px;
}#game td:hover{background-color:#AAA;
}/* 為雷區(qū) */
.landMine{background-image:url('http://labfile.oss.aliyuncs.com/courses/144/mine.png');background-position:center;background-repeat:no-repeat;
}/* 鼠標右鍵點擊標志 */
.flag{background-image:url('http://labfile.oss.aliyuncs.com/courses/144/flag.png');background-position:center;background-repeat:no-repeat;
}/* 不是雷區(qū),普通區(qū) */
#game td.normal{border:2px solid #EEE;background-color:#AAA;
}#control{display: inline;float: left;margin-left: 30px;width: 200px;height: auto;text-align: center;
}#restMine{margin-top: 10%;font-size: 16px;
}#control form{margin-top:10%;
}#control fieldset{height: 100px;
}#control form legend{text-align:left;margin-left: 10px;
}#control label{font-size: 14px;padding: 10px;
}#useTime{margin-top: 10%;font-size:16px;
}#startGame {margin-top: 20px;padding: 0.5em;width: 100px;
}#info{text-align: left;margin-top: 20px;
}#info ul{text-indent: 10px;font-size: 13px;
}
創(chuàng)建表格
function $(id) {return typeof id==="string"?document.getElementById(id):null;
}//作為全局的函數(shù)
傳入行數(shù),列數(shù)來創(chuàng)建表格
//創(chuàng)建表格函數(shù)
function createTable(rowCount,colCount){var table=$('game');empty(table); //每次創(chuàng)建都要先清空表格for(var i=0;i<rowCount;i++){var tr=document.createElement('tr');for(var j=0;j<colCount;j++) {var td = document.createElement('td');td.id = 'm_' + i + '_' + j; //綁定一個idtr.appendChild(td);}table.appendChild(tr);}
};//清空子節(jié)點
function empty(node){while(node.hasChildNodes()) {node.removeChild(node.firstChild);}
};
掃雷.js
//初始化表格并監(jiān)聽難度點擊事件
var jms=new JMS('game');
function initTable() {var hardList=document.getElementsByName("difficultLevel");var tdCountArr=[10,15,20];//難度的數(shù)組var flag=true;//監(jiān)聽難度點擊事件for(var i=0;i<hardList.length;i++){(function(j){hardList[j].addEventListener('click',function(){if(jms!=null&&jms.rowCount!=tdCountArr[j]) {if(jms.mineCount!==0){//確認改變if(window.confirm("確認改變難度等級嗎?")) {flag=true;//更新數(shù)據(jù)jms.colCount = tdCountArr[j];jms.rowCount = tdCountArr[j];jms.end();//之前的游戲結(jié)束clearInterval(timer);//清除計時器jms. initGame();//初始化游戲數(shù)據(jù)//重建表createTable(jms.rowCount,jms.colCount);}else{flag=false;}}}if(!flag){return false;}})})(i);}
}//標記時的回調(diào)函數(shù),更新雷數(shù)
jms.markCallback=function (count) {return $('restMineCount').innerHTML=count;
}//結(jié)束的回調(diào)函數(shù),計時,雷數(shù)顯示清零
jms.endCallback=function () {$('restMineCount').innerHTML=0;$('useTimeSecond').innerHTML=0;
}//全局計時
var timer=null;
//開始游戲
initTable(); //監(jiān)聽點擊改變難度事件
function startGame() {createTable(10,10); //初始創(chuàng)建一個10*10表//點擊開始新游戲$('startGame').addEventListener('click',function () {jms.play(); //游戲開始接口jms.begin(); //游戲正式開始$('restMineCount').innerHTML=jms.mineCount-jms.remarkedMine; //顯示雷的數(shù)目//計時開始timer=setInterval(function (){$('useTimeSecond').innerHTML=parseInt((new Date()-jms.startTime)/1000); //更新顯示的時間if(!jms.status){//表示已經(jīng)停止clearInterval(timer);$('useTimeSecond').innerHTML=parseInt((jms.endTime-jms.startTime)/1000); //不能讓alert阻止進程,導致計時不停止}},1000);});
}
startGame();
jms.js代碼
(function(){function $(id) {return typeof id==="string"?document.getElementById(id):null;}var JMS=function (id,rowCount,colCount) {if(!(this instanceof JMS)) {return new JMS();}this.startTime=null;//開始時間this.endTime=null;//結(jié)束時間this.rowCount=rowCount||10;//行數(shù),默認為10this.colCount=colCount||10;//列數(shù)this.table=$(id);//表格區(qū)this.tdArr=this.table.getElementsByTagName('td');//一個個的小塊this.status=false;//游戲的狀態(tài),true為開始,false為結(jié)束this.arr=[];//td對應的數(shù)值數(shù)組this.remarkedMine=0;//標記的雷數(shù)this.mineCount=10;//雷數(shù)this.currentStepCount=0;//步數(shù),包括自動打開的空白區(qū)域和點擊的非0區(qū)域this.markCallback=null;//標記的回調(diào)函數(shù),用于實時更新雷數(shù)this.endCallback=null;//結(jié)束的回調(diào)函數(shù)this.doc=document;//當前文檔的引用this.doc.oncontextmenu=function () { //右鍵禁止默認行為return false;}}JMS.prototype={//初始化數(shù)組,全部為0initGame:function () {//td對應的數(shù)值數(shù)組,全為0for(var i=0;i<this.rowCount;i++){this.arr[i]=[];for(var j=0;j<this.colCount;j++){this.arr[i][j]=0;}}//產(chǎn)生隨機雷數(shù)this.mineCount=parseInt(Math.random()*5)+this.rowCount*4; //可以根據(jù)自己選擇調(diào)試this.startTime=new Date();this.endTime=null;this.currentStepCount=0;this.remarkedMine=0;this.status=true;},//數(shù)組更新為雷區(qū),用 9 表示landMine:function(){var tempArr=[],allCount=this.colCount*this.rowCount-1;for(var i=0;i<this.mineCount;i++){var randomNum=this.getRandom(0,allCount);var colsRows=this.getColRow(randomNum);if(colsRows in tempArr){//在數(shù)組中,跳走i--;、continue;}tempArr[tempArr.length]=randomNum;this.arr[colsRows.rows][colsRows.cols]=9;}},//產(chǎn)生一個隨機數(shù)getRandom:function(begin,end){return parseInt(Math.random()*(end-begin))+begin;},//得到行列,用% / 得到getColRow:function(allCount){return {cols:allCount%this.colCount,rows:parseInt(allCount/this.rowCount)}},//遍歷表格,得到數(shù)組calculateNoLandMineCount:function () {for(var i=0;i<this.rowCount;i++) {for (var j = 0; j < this.colCount; j++) {if (this.arr[i][j] == 9) {continue;}if (i > 0 && j > 0) {if (this.arr[i - 1][j - 1] == 9) {this.arr[i][j]++;}}if (i > 0) {if (this.arr[i - 1][j] == 9) {this.arr[i][j]++;}}if (i > 0 && j < this.colCount - 1) {if (this.arr[i - 1][j + 1] == 9)this.arr[i][j]++;}if (j > 0) {if (this.arr[i][j - 1] == 9) {this.arr[i][j]++;}}if (j < this.rowCount - 1) {if (this.arr[i][j + 1] == 9) {this.arr[i][j]++;}}if (i < this.rowCount - 1 && j > 0) {if (this.arr[i + 1][j - 1] == 9)this.arr[i][j]++;}if (i < this.rowCount - 1) {if (this.arr[i + 1][j] == 9)this.arr[i][j]++;}if (i < this.rowCount - 1 && j < this.colCount - 1) {if (this.arr[i + 1][j + 1] == 9)this.arr[i][j]++;}}}},//綁定事件bindCells:function(){//保留全局的this,到綁定事件時this會更改var self=this;for(var i=0;i<this.rowCount;i++) {for (var j = 0; j < this.colCount; j++) {//閉包綁定事件(function (i, j) {$('m_' + i + '_' + j).onmousedown=function (event) {var btn = event.button; var className = this.className;if (btn == 2) {// 標記,前面阻止右鍵默認行為,btn為2表示點擊鼠標右鍵,為1表示左鍵if (className !== 'flag') {this.className = 'flag';self.remarkedMine++;} else {this.className = '';self.remarkedMine--;}//調(diào)用標記回調(diào)函數(shù),在掃雷.js中定義的回調(diào)函數(shù)if(self.markCallback){self.markCallback(self.mineCount-self.remarkedMine);}} else {// 打開self.OpenItem.call(self, this, i, j);}}})(i, j);}}},//打開,OpenItem:function (obj,row,col) {if(this.arr[row][col]!==9){this.currentStepCount++;if(this.arr[row][col]!==0){obj.innerHTML=this.arr[row][col];}obj.className='normal';if(this.currentStepCount+this.remarkedMine==this.colCount*this.rowCount-1){ //成功this.success();}obj.onmousedown=null;if (this.arr[row][col] == 0) {this.showNoLandMine.call(this, row, col);}}else{this.fail();}},//顯示無雷區(qū)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&&y==j)){var ele=$('m_'+i+'_'+j);if(ele&&ele.className==''){this.OpenItem.call(this, ele, i, j);}}}}},//顯示雷區(qū)方塊showLandMine:function () {for(var i=0;i<this.rowCount;i++){for(var j=0;j<this.colCount;j++){//為雷區(qū)if(this.arr[i][j]==9){$('m_'+i+"_"+j).className='landMine';}}}},//顯示所有的方塊showAll:function () {for(var i=0;i<this.rowCount;i++){for(var j=0;j<this.colCount;j++){if(this.arr[i][j]==9){$('m_'+i+"_"+j).className='landMine';}else{if(this.arr[i][j]!=0){$('m_'+i+"_"+j).innerHTML=this.arr[i][j];}$('m_'+i+"_"+j).className='normal';}}}},//清除信息,clearIfo:function () {for(var i=0;i<this.rowCount;i++){for(var j=0;j<this.colCount;j++){$('m_'+i+'_'+j).innerHTML='';$('m_'+i+'_'+j).className='';}}},//清除綁定clearBind:function(){for(var i=0;i<this.rowCount;i++){for(var j=0;j<this.colCount;j++){$('m_'+i+'_'+j).onmousedown=null;}}},//游戲成功success:function () {this.end();this.clearBind();this.showAll();setTimeout(function (){alert("Congratulation!")},100);this.clearIfo();},//游戲失敗,結(jié)束->顯示所有->清除綁定->顯示結(jié)束(js單線程,有一定的時間延遲,設(shè)置一個定時器)fail:function () {this.end();this.showAll();this.clearBind();setTimeout(function (){alert("GAME OVER")},100);},//開始游戲接口 ,初始化游戲->生成雷區(qū)數(shù)組->計算非雷數(shù)play:function () {this.initGame();this.landMine();this.calculateNoLandMineCount();},//游戲開始 ,步數(shù)、標記雷數(shù)為0->begin:function () {this.currentStepCount=0;this.remarkedMine=0;this.clearIfo();this.bindCells();},//游戲結(jié)束,結(jié)束時間->狀態(tài)更改->結(jié)束回調(diào)函數(shù)end:function () {this.endTime=new Date();this.status=false;if(this.endCallback){this.endCallback();}}}window.JMS=JMS; //對象全局化
})();
總結(jié)
主要使用 JavaScript 實現(xiàn)了網(wǎng)頁版的經(jīng)典小游戲掃雷,代碼有一些冗余,根據(jù)網(wǎng)上提供的思路自己寫的,代碼有一些小BUG,是單選點擊BUG。僅保存,具體學習案例和代碼開頭已經(jīng)給出。讀者可以根據(jù)自己的需要選擇。本文只作為學習筆記
總結(jié)
以上是生活随笔為你收集整理的网页版扫雷小游戏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。