HTML 实现扫雷游戏

HTML 实现扫雷游戏

项目原理:

扫雷游戏的规则很简单:

游戏面板上有一些格子,每个格子中有一个数字(空白表示数字为 0)或是地雷,格子中的数字表示格子周围格子中地雷的数量。玩家要做的就是把数字格子找出来,时间花的越少越好。

除边界上的格子外,每个格子周围有 8 个格子:上、下、左、右、4 个斜角。所以数字范围是 0~8。

所以我们的算法如下:

根据用户选择的难易程度(有初、中、高三个级别,级别越高地雷和格子数量越多),随机产生一定个数的地雷并随机放在格子中。然后遍历格子,计算每个格子中的数字,标记在格子上。玩家左键点击格子时显示格子内容(如果遇到地雷则挑战失败,游戏结束),右键点击格子时标记格子为地雷,真到正确标记所有地雷并打开所有非地雷格子,挑战成功,游戏结束。

小技巧:由于格子中数字范围是 0~8,所以为了便于计算,我们可以把地雷所在的格子中的数字记为 9

项目的目录结构:

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

图片下载地址:

 https://labfile.oss.aliyuncs.com/courses/144/mine.png
 https://labfile.oss.aliyuncs.com/courses/144/flag.png

下面将从页面布局开始,一步一步完成所有代码的编写

首先我们需要有一个面板来显示游戏信息,包括剩余地雷个数、所用时间、难度级别等。因为格子数量不是固定的,所以我们先不画格子,放在 JS 代码中绘制。

创建 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">
          剩余雷数:<span class="light red" id="landMineCount">0</span></div>
        <div class="tip">
          持续时间: <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;
}

完成这步后,浏览器打开看看

index.html

效果如下:

图片描述

左边空白处用于显示格子。

下面就要画格子了,为了让代码更清晰,我们把游戏实现部分和调用部分分开,游戏实现部分放在跟 index.html 同目录下的 jms.js 中,游戏调用部分放在同目录下的 index.js 中。

画格子需要传入一些参数,如放格子的表格的 id,格子的数量(用行数和列数表示)。另外,游戏的其他数据也要进行初始化。

//在jms.js中
(function () {
  // 初始化扫雷对象,初始化数据
  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; //格子行数
    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();
  };

  // 在 JMS 的原型中创建格子
  JMS.prototype = {
    //画格子
    drawMap: function () {
      var tds = [];
      // 为了兼容浏览器
      if (
        window.ActiveXObject &&
        parseInt(navigator.userAgent.match(/msie ([\d.]+)/i)[1]) < 8
      ) {
        // 创建引入新的 css 样式文件
        var css = '#JMS_main table td{background-color:#888;}',
          // 获取 head 标签
          head = this.doc.getElementsByTagName('head')[0],
          // 创建 style 标签
          style = this.doc.createElement('style');
        style.type = 'text/css';
        if (style.styleSheet) {
          // 将 css 样式赋给 style 标签
          style.styleSheet.cssText = css;
        } else {
          // 在 style 标签中创建节点
          style.appendChild(this.doc.createTextNode(css));
        }
        // 再将 style 标签创建为 head 标签的子标签
        head.appendChild(style);
      }
      // 循环创建表格
      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到Table
    setTableInnerHTML: function (table, html) {
      if (navigator && navigator.userAgent.match(/msie/i)) {
        // 在 table 的 owner document 内创建 div
        var temp = table.ownerDocument.createElement('div');
        // 创建表格的 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.html,格子已经可以显示出来了,效果如下:

图片描述

点击右边的难度选择,可以看到格子的数量变化。

现在,我们开始对游戏初始化,主要分三步:

  1. 把所有格子(代码中用一个数组表示)初始化为 0;
  2. 随机生成地雷个数,把地雷随机放到数组中,数组项值设置为 9;
  3. 计算其他格子中的数字,值放入数组中。

jms.jsJMS.prototype 内加入如下代码:

//在jms.js中JMS.prototype内加入
//初始化,一是设置数组默认值为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);
    this.markLandMineCount = 0;
    this.beginTime = null;
    this.endTime = null;
    this.currentSetpCount = 0;
},
//把是地雷的数组项的值设置为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]++;
            }
        }
    }
},
//获取一个随机数
selectFrom: function (iFirstValue, iLastValue) {
    var iChoices = iLastValue - iFirstValue + 1;
    return Math.floor(Math.random() * iChoices + iFirstValue);
},
//通过数值找到行数和列数
getRowCol: function (val) {
    return {
        row: parseInt(val / this.colCount),
        col: val % this.colCount
    };
},

给格子添加点击事件

现在,该给格子添加点击事件了,当左键点击时,显示出格子中的数字(如果是地雷就挑战失败,结束游戏),右键点击时标记为地雷。

另外,第一次点击格子(往往带有运气成分)如果周围有空白区域会直接展开。

jms.js 中的这部分代码如下:

//在jms.js中JMS.prototype内加入
//获取元素
$: function (id) {
    return this.doc.getElementById(id);
},
//给每个格子绑定点击事件(左键和右键)
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.className = "normal";
        if (this.currentSetpCount + this.landMineCount == this.rowCount * this.colCount) {
            this.success();
        }
        obj.onmousedown = null;
        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 + "_" + 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 + "_" + j).className = "landMine";
            } else {
                var ele=this.$("m_" + i + "_" + j);
                if (this.arrs[i][j] != 0)
                    ele.innerHTML = this.arrs[i][j];
                ele.className = "normal";
            }
        }
    }
},
//清除显示的格子信息
hideAll: function () {
    for (var i = 0; i < this.rowCount; i++) {
        for (var j = 0; j < this.colCount; j++) {
            var tdCell = this.$("m_" + i + "_" + 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 + "_" + j);
            tdCell.onmousedown = null;
        }
    }
},

添加游戏控制功能

到现在为止,游戏主要部分已经完成,下面要做的就是添加游戏控制功能,让游戏正常运行起来,主要有以下几步:

  1. 给游戏开始按钮添加点击事件,重置游戏参数;
  2. 游戏开始后开始记时;
  3. 游戏结束就停止记时并提示。

jms.js 中添加游戏入口和开始功能:

//在 jms.js 中 JMS.prototype 内加入
//游戏开始
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!");
},
//入口
play: function () {
    this.init();
    this.landMine();
    this.calculateNoLandMineCount();
},

index.js 中给开始按钮添加事件,开始游戏,并显示游戏时间和剩余地雷个数:

//在index.js的init中,jms = JMS("landmine", rowCount, colCount, minLandMineCount, maxLandMineCount); 之后加入
jms.endCallBack = function () {
  clearInterval(timeHandle);
};
jms.landMineCallBack = function (count) {
  landMineCountElement.innerHTML = count;
};

//为“开始游戏”按钮绑定事件
beginButton.onclick = function () {
  jms.play(); //初始化

  //显示地雷个数
  landMineCountElement.innerHTML = jms.landMineCount;

  //开始
  jms.begin();

  //更新花费的时间
  timeHandle = setInterval(function () {
    timeShow.innerHTML = parseInt((new Date() - jms.beginTime) / 1000);
  }, 1000);
};

jms.js 完整代码

jms.js 中写入以下代码:

(function () {
  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; //格子行数
    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();
  };

  JMS.prototype = {
    //画格子
    drawMap: function () {
      var tds = [];
      if (
        window.ActiveXObject &&
        parseInt(navigator.userAgent.match(/msie ([\d.]+)/i)[1]) < 8
      ) {
        var css = '#JMS_main table td{background-color:#888;}',
          head = this.doc.getElementsByTagName('head')[0],
          style = this.doc.createElement('style');
        style.type = 'text/css';
        if (style.styleSheet) {
          style.styleSheet.cssText = css;
        } else {
          style.appendChild(this.doc.createTextNode(css));
        }
        head.appendChild(style);
      }
      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.setTableInnerHTML(this.table, tds.join(''));
    },
    //添加HTML到Table
    setTableInnerHTML: function (table, html) {
      if (navigator && navigator.userAgent.match(/msie/i)) {
        var temp = table.ownerDocument.createElement('div');
        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;
      }
    },
    //初始化,一是设置数组默认值为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
      );
      this.markLandMineCount = 0;
      this.beginTime = null;
      this.endTime = null;
      this.currentSetpCount = 0;
    },
    //把是地雷的数组项的值设置为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]++;
          }
        }
      }
    },
    //获取一个随机数
    selectFrom: function (iFirstValue, iLastValue) {
      var iChoices = iLastValue - iFirstValue + 1;
      return Math.floor(Math.random() * iChoices + iFirstValue);
    },
    //通过数值找到行数和列数
    getRowCol: function (val) {
      return {
        row: parseInt(val / this.colCount),
        col: val % this.colCount,
      };
    },
    //获取元素
    $: function (id) {
      return this.doc.getElementById(id);
    },
    //给每个格子绑定点击事件(左键和右键)
    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.className = 'normal';
        if (
          this.currentSetpCount + this.landMineCount ==
          this.rowCount * this.colCount
        ) {
          this.success();
        }
        obj.onmousedown = null;
        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 + '_' + 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 + '_' + j).className = 'landMine';
          } else {
            var ele = this.$('m_' + i + '_' + j);
            if (this.arrs[i][j] != 0) ele.innerHTML = this.arrs[i][j];
            ele.className = 'normal';
          }
        }
      }
    },
    //清除显示的格子信息
    hideAll: function () {
      for (var i = 0; i < this.rowCount; i++) {
        for (var j = 0; j < this.colCount; j++) {
          var tdCell = this.$('m_' + i + '_' + 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 + '_' + 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!');
    },
    //入口
    play: function () {
      this.init();
      this.landMine();
      this.calculateNoLandMineCount();
    },
  };

  window.JMS = JMS;
})();

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);
  jms.endCallBack = function () {
    clearInterval(timeHandle);
  };
  jms.landMineCallBack = function (count) {
    landMineCountElement.innerHTML = count;
  };

  //为“开始游戏”按钮绑定事件
  beginButton.onclick = function () {
    jms.play(); //初始化

    //显示地雷个数
    landMineCountElement.innerHTML = jms.landMineCount;

    //开始
    jms.begin();

    //更新花费的时间
    timeHandle = setInterval(function () {
      timeShow.innerHTML = parseInt((new Date() - jms.beginTime) / 1000);
    }, 1000);
  };
}

到此我们的网页版扫雷就完成了。打开 index.html 文件,就可以开始游戏了。

图片描述

总结

主要使用 JavaScript 实现了网页版的经典小游戏扫雷。相信通过本项目,可以提高大家对 JavaScript 的理解与运用能力。此外,大家也可以学习到如何使用 JavaScript 语言来抽象、封装游戏中的对象
源码:
https://download.csdn.net/download/Deng872347348/85301530

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deng872347348

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值