日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

前端经典练手项目|用 JavaScript 实现网页版扫雷

發(fā)布時間:2023/12/10 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前端经典练手项目|用 JavaScript 实现网页版扫雷 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

相信大家都玩過掃雷這個經典的小游戲,它規(guī)則簡單但耐玩。你有沒有想過自己動手開發(fā)一個呢?今天我們就教你做一個網頁版的掃雷,先上一張效果截圖:

知識點

  • javascript

  • css3

  • 掃雷原理

實驗原理

在開始開發(fā)之前,我們先來設計一下游戲算法。

掃雷游戲的規(guī)則很簡單:

游戲面板上有一些格子,每個格子中有一個數(shù)字(空白表示數(shù)字為 0)或是地雷,格子中的數(shù)字表示格子周圍格子中地雷的數(shù)量。玩家要做的就是把數(shù)字格子找出來,時間花的越少越好。

除邊界上的格子外,每個格子周圍有 8 個格子:上、下、左、右、4 個斜角。所以數(shù)字范圍是 0~8。

所以我們的算法如下:

根據(jù)用戶選擇的難易程度(有初、中、高三個級別,級別越高地雷和格子數(shù)量越多),隨機產生一定個數(shù)的地雷并隨機放在格子中。然后遍歷格子,計算每個格子中的數(shù)字,標記在格子上。玩家左鍵點擊格子時顯示格子內容(如果遇到地雷則挑戰(zhàn)失敗,游戲結束),右鍵點擊格子時標記格子為地雷,真到正確標記所有地雷并打開所有非地雷格子,挑戰(zhàn)成功,游戲結束。

小技巧:由于格子中數(shù)字范圍是 0~8,所以為了便于計算,我們可以把地雷所在的格子中的數(shù)字記為 9。

代碼獲取

$ git clone https://github.com/shiyanlou/js-minesweeper

先建立下面的目錄結構:

minesweeper|__index.html|__index.css|__index.js|__jms.js

然后我們需要在項目目錄中放入實驗要用到的地雷和旗幟的圖片, 通過下面的命令下載圖片:

$ wget http://labfile.oss.aliyuncs.com/courses/144/mine.png $ wget http://labfile.oss.aliyuncs.com/courses/144/flag.png

實驗步驟

下面將從頁面布局開始,一步一步完成所有代碼的編寫。

頁面布局

首先我們需要有一個面板來顯示游戲信息,包括剩余地雷個數(shù)、所用時間、難度級別等。因為格子數(shù)量不是固定的,所以我們先不畫格子,放在 JS 代碼中繪制。

創(chuàng)建 index.html 文件

添加如下代碼并保存:

<!DOCTYPE html> <html> <head><meta charset="utf-8" /><title>JavaScript版掃雷</title><link rel="stylesheet" type="text/css" href="index.css"/> </head> <body><div id="JMS_main" class="main"><table id="landmine"></table><div id="operation"><div class="tip">剩余雷數(shù):<span class="light red" id="landMineCount">0</span> 個</div><div class="tip">持續(xù)時間: <span class="light f60" id="costTime">0</span> 秒</div><fieldset><legend>難度選擇:</legend><input type="radio" name="level" id="llevel" checked="checked" value="10" /><label for="llevel">初級(10*10)</label><br /><input type="radio" name="level" id="mlevel" value="15" /><label for="mlevel">中級(15*15)</label><br /><input type="radio" name="level" id="hlevel" value="20" /><label for="hlevel">高級(20*20)</label><br /></fieldset><input type="button" id="begin" value="開始游戲" /><br /><div class="tip txtleft">提示:<ul><li>1、點擊“開始游戲”游戲開始計時</li><li>2、游戲過程中點擊“開始游戲”將開始新游戲</li></ul></div></div></div><script src="jms.js"></script><script src="index.js"></script> </body> </html>

頁面布局樣式

然后需要調整面板上游戲信息的位置,添加一些樣式,在 index.css 中添加如下代碼并保存:

.main {margin:10px auto;padding:20px;background:#EEE;width:600px;zoom:1; } .main table {background:#CCC;float:left; } .main table td {border:2px outset #EEE;font-size:20px;width:32px;height:32px;text-align:center;cursor:pointer; } .main table td:hover {background-color:#AAA; } .main #operation {width:180px;float:right;text-align:center; } .landMine {background-image:url(mine.png);background-position:center;background-repeat:no-repeat; } .main table td.normal {border:2px solid #EEE;background-color:#AAA; } .main table td.normal:hover {background-color:#AAA; } .flag {background-image:url(flag.png);background-position:center;background-repeat:no-repeat; } .main:after {clear: both;display: block;content: "";line-height: 0;height: 0;visibility:hidden; } .main .tip {font-size:14px;margin:5px; } .main .tip ul { } .main .tip ul li {margin:5px 0;line-height:20px; } .main .light{font-size:30px; } .main .red {color:red; } .main .f60 {color:#F60; } .main input[type=button] {padding:2px 10px;margin:5px;font-size:20px;cursor:pointer; } .main .txtleft {text-align:left; } .main input[type='radio'], .main fieldset label {cursor:pointer; } .main fieldset {margin:10px 0;line-height:25px; }

完成這步后,在 Preview 或 Mini Browser 中打開 index.html,效果如下:

左邊空白處用于顯示格子。

繪制格子

完成上面的步驟后,下面就要畫格子了,為了讓代碼更清晰,我們把游戲實現(xiàn)部分和調用部分分開,游戲實現(xiàn)部分放在跟 index.html 同目錄下的 jms.js 中,游戲調用部分放在同目錄下的 index.js 中。

畫格子需要傳入一些參數(shù),如放格子的表格的 id,格子的數(shù)量(用行數(shù)和列數(shù)表示)。另外,游戲的其他數(shù)據(jù)也要進行初始化。

//在jms.js中 (function () {// 初始化掃雷對象,初始化數(shù)據(jù)var JMS = function (id,rowCount,colCount, minLandMineCount, maxLandMineCount) {if (!(this instanceof JMS))return new JMS(id, rowCount, colCount, minLandMineCount, maxLandMineCount);this.doc = document;this.table = this.doc.getElementById(id);//畫格子的表格this.cells = this.table.getElementsByTagName("td");//小格子this.rowCount = rowCount || 10;//格子行數(shù)this.colCount = colCount || 10;//格子列數(shù)this.landMineCount = 0;//地雷個數(shù)this.markLandMineCount = 0;//標記的地雷個數(shù)this.minLandMineCount = minLandMineCount || 10;//地雷最少個數(shù)this.maxLandMineCount = maxLandMineCount || 20;//地雷最多個數(shù)this.arrs = [];//格子對應的數(shù)組this.beginTime = null;//游戲開始時間this.endTime = null;//游戲結束時間this.currentSetpCount = 0;//當前走的步數(shù)this.endCallBack = null;//游戲結束時的回調函數(shù)this.landMineCallBack = null;//標記為地雷時更新剩余地雷個數(shù)的回調函數(shù)this.doc.oncontextmenu = function () {//禁用右鍵菜單return false;};this.drawMap();};// 在 JMS 的原型中創(chuàng)建格子JMS.prototype = {//畫格子drawMap: function () {var tds = [];// 為了兼容瀏覽器if (window.ActiveXObject && parseInt(navigator.userAgent.match(/msie ([\d.]+)/i)[1]) < 8) {// 創(chuàng)建引入新的 css 樣式文件var css = '#JMS_main table td{background-color:#888;}',// 獲取 head 標簽head = this.doc.getElementsByTagName("head")[0],// 創(chuàng)建 style 標簽style = this.doc.createElement("style");style.type = "text/css";if (style.styleSheet) {// 將 css 樣式賦給 style 標簽style.styleSheet.cssText = css;} else {// 在 style 標簽中創(chuàng)建節(jié)點style.appendChild(this.doc.createTextNode(css));}// 再將 style 標簽創(chuàng)建為 head 標簽的子標簽head.appendChild(style);}// 循環(huán)創(chuàng)建表格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("</tr>");}this.setTableInnerHTML(this.table, tds.join(""));},//添加HTML到TablesetTableInnerHTML: function (table, html) {if (navigator && navigator.userAgent.match(/msie/i)) {// 在 table 的 owner document 內創(chuàng)建 divvar temp = table.ownerDocument.createElement('div');// 創(chuàng)建表格的 tbody 內容temp.innerHTML = '<table><tbody>' + html + '</tbody></table>';if (table.tBodies.length == 0) {var tbody = document.createElement("tbody");table.appendChild(tbody);}table.replaceChild(temp.firstChild.firstChild, table.tBodies[0]);} else {table.innerHTML = html;}}};window.JMS = JMS; })();

上面的代碼中,部分代碼是為了兼容 IE 瀏覽器,可忽略。

在 index.js 的調用代碼中,我們需要綁定難度選擇按鈕的事件,然后調用上面定義的 JMS,開始繪制格子。

在 index.js 中添加如下代碼并保存:

//在index.js中 var jms = null,timeHandle = null; window.onload = function () {var radios = document.getElementsByName("level");for (var i = 0, j = radios.length; i < j; i++) {radios[i].onclick = function () {if (jms != null)if (jms.landMineCount > 0)if (!confirm("確定結束當前游戲?"))return false;var value = this.value;init(value, value, value * value / 5 - value, value * value / 5);document.getElementById("JMS_main").style.width = value * 40 + 180 + 60 + "px";}}init(10, 10); }; function init(rowCount, colCount, minLandMineCount, maxLandMineCount) {var doc = document,landMineCountElement = doc.getElementById("landMineCount"),timeShow = doc.getElementById("costTime"),beginButton = doc.getElementById("begin");if (jms != null) {clearInterval(timeHandle);timeShow.innerHTML = 0;landMineCountElement.innerHTML = 0;}jms = JMS("landmine", rowCount, colCount, minLandMineCount, maxLandMineCount); }

然后在瀏覽器中打開 index.html,格子已經可以顯示出來了,效果如下:

點擊右邊的難度選擇,可以看到格子的數(shù)量變化。

游戲初始化

現(xiàn)在,我們開始對游戲初始化,主要分三步:

  • 把所有格子(代碼中用一個數(shù)組表示)初始化為 0

  • 隨機生成地雷個數(shù),把地雷隨機放到數(shù)組中,數(shù)組項值設置為 9

  • 計算其他格子中的數(shù)字,值放入數(shù)組中

  • 在 jms.js 中 JMS.prototype 內加入如下代碼:

    //在jms.js中JMS.prototype內加入 //初始化,一是設置數(shù)組默認值為0,二是確定地雷個數(shù) 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);this.markLandMineCount = 0;this.beginTime = null;this.endTime = null;this.currentSetpCount = 0; }, //把是地雷的數(shù)組項的值設置為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;} }, //計算其他格子中的數(shù)字 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]++;}}} }, //獲取一個隨機數(shù) selectFrom: function (iFirstValue, iLastValue) {var iChoices = iLastValue - iFirstValue + 1;return Math.floor(Math.random() * iChoices + iFirstValue); }, //通過數(shù)值找到行數(shù)和列數(shù) getRowCol: function (val) {return {row: parseInt(val / this.colCount),col: val % this.colCount}; },

    給格子添加點擊事件

    現(xiàn)在,該給格子添加點擊事件了,當左鍵點擊時,顯示出格子中的數(shù)字(如果是地雷就挑戰(zhàn)失敗,結束游戲),右鍵點擊時標記為地雷。

    另外,第一次點擊格子(往往帶有運氣成分)如果周圍有空白區(qū)域會直接展開。

    篇幅有限,點擊閱讀原文,即可查看完整課程內容 + 代碼? ????????????

    我們還為你準備了在線的實驗環(huán)境,點擊一下即可開始體驗這個項目。學編程,當然要邊練邊學了~

    PC 端登陸,開始學習之旅https://www.shiyanlou.com/courses/144

    總結

    以上是生活随笔為你收集整理的前端经典练手项目|用 JavaScript 实现网页版扫雷的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。