js扫雷游戏
Gnijooo 人气:0界面
考虑到简单,一般,困难三个扫雷区域的格子数都不同,所以界面上的扫雷区域是用js动态生成。
先搭好整体html框架:
<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>
首先写一个MineSweeper()构造方法:
function MineSweeper(tr, td, mineNum) { this.tr = tr; //行 this.td = td; //列 this.mineNum = mineNum; //雷数 this.area = []; //存取每个格子信息 this.doms = []; //存储格子DOM,用来动态创建DOM this.lastMineNum = mineNum; //剩余雷数 this.parent = document.querySelector('.mine'); this.num = document.querySelector('.last .mineNum'); }
扫雷区域用一个二维数组表示并存储:
/* * 扫雷游戏区域area(二维数组) * [ * [type: mine/number, x1, y1], * [type: mine/number, x2, y2], * ... , * [type: mine/number, xn, yn] * ] */
其中type有两个值,mine表示当前格子是一个雷;number表示当前格子是一个数字。
在构造方法的原型上添加方法创建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); //往行中添加列 } 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(); //创建表格 this.parent.innerHTML = ""; this.create(); } //创建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; //当前选中状态的按钮 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>
更新数字
遍历扫雷区域数组,当遇到雷时,取到其周围的格子,如果是数字,则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; } } } };
实现效果:
加载全部内容