目录

  • 扫雷小游戏
    • 预览
    • 游戏讲解
    • 界面
    • 逻辑设计
      • 寻找目标格子周围格子
      • 更新数字
      • 游戏结束
      • 开始游戏
    • 总结
    • 完整代码
      • HTML
      • css
      • js

扫雷小游戏

预览

游戏讲解

扫雷是一个益智游戏,通过格盘上的数字提醒我们当前格子周围有几个雷,踩到雷时游戏结束。利用这个游戏规则,可以找到每个雷,遍历其周围八个格子。
以一个九宫格为单元,将雷周围的八个格子(若不是雷)的数字都+1操作

若周围格子出现雷,则不对其+1,不改变其雷的属性:

于是可以继续得到:

以此类推,继续遍历,直到普及整个格盘(这里以四个雷为例):

从上面格盘可以清楚的知道,每个数字的周围(以一个九宫格为单元)都有其本身数字大小的雷数,如:1周围有1个雷,3周围有三个雷。

界面

考虑到简单,一般,困难三个扫雷区域的格子数都不同,所以界面上的扫雷区域是用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,用来动态创建DOMthis.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添加到界面
};

逻辑设计

寻找目标格子周围格子

在构造函数的原型上添加一个方法,用来寻找目标格子周围的格子。并标记是数字or雷or四个角?以便后续是否对指定格子做+1操作。如果是雷则不加,如果在四个角则看情况+1操作。
找目标格子(target)周围格子的思路:

/*
* around...
*  [x-1, y-1]   [x, y-1]   [x+1, y-1]
*
*  [x-1, y]      target    [x+1, y]
*
*  [x-1, y+1]   [x, y+1]   [x+1, y+1]
* 用双层for循环
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++) {/*排除四个角and周围是雷and本身的情况,以便后续对周围格子数值进行重叠的number++操作*/if(i < 0 || j < 0 || i > this.td - 1 || j > this.tr - 1 ||  //排除四个角(i == x && j == y) ||                            //排除周围是雷this.area[j][i].type === 'mine'               //排除本身, [j][i]? --> 行列,非循环表示的坐标){continue;}result.push([j, i]);}}return result;  //[j][i] --> 表行列,而上面的i,j表示的是坐标x,y;这里x表示列,y表示行
};

更新数字

遍历扫雷区域数组,当遇到雷时,取到其周围的格子,如果是数字,则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都要+1this.area[nums[k][0]][nums[k][1]].value += 1;}}}
};

游戏结束

踩到雷时,为当前点击的雷添加一个样式(这里为其添加一个红色背景),显示所有雷,并且玩家无法继续点击扫雷区域。

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();}}

总结

以上仅讲述了核心模块。思路仅供参考。

完整代码

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>

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;
}

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';//标记小旗子,则剩余雷数-1if(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都要+1this.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();

小清新版js扫雷(使用原生js)相关推荐

  1. JS|使用原生js实现拦截器

    除夕快乐啊,最近一直在开发前后端都没时间写博客了,正好把最近研究的拦截器拿出来卖弄一下- 什么是拦截器? 通俗点讲,就是在某一组条件条件未达到的情况下,禁止访问某一组页面:咱们举个栗子,我有一个页面, ...

  2. (30个原生js挑战)原生js实现钟表

    紧接着昨天的实例,第二个是原生js实现钟表特效. 首先介绍下大致思路,首先要用css把时针分针和秒针画出来.然后根据钟表中,角度和时间的算法关系. 设置角度. 最后使用定时器,每秒运行一次. 需要注意 ...

  3. 原生js更改html,原生js更改css样式的两种方式

    原生js更改css样式的两种方式 发布时间:2020-08-30 01:46:17 来源:脚本之家 阅读:148 作者:外婆的彭湖湾 下面我给大家介绍的是原生js更改CSS样式的两种方式: 1. 通过 ...

  4. php日期控件calendar.js,轻量级的原生js日历插件calendar.js使用指南

    使用说明: 需要引入插件calendar.js/calendar.min.js 须要引入calendar.css 样式表,可以自定义自己想要的皮肤 本日历插件支持cmd模块化 如下调用:xvDate( ...

  5. html js 设置样式,原生js设置样式 笔记:JS设置CSS样式的几种方式

    document(id名).style.backgroundColor = "ren" css里的属性有-的就去掉将首字母大写. js如何添加CSS样式中的class添加属性 用J ...

  6. 原生js输出html5,原生JS+HTML5实现的可调节写字板功能示例

    本文实例讲述了原生JS+HTML5实现的可调节写字板功能.分享给大家供大家参考,具体如下: 前面一篇介绍了<JS+HTML5 Canvas实现简单的写字板功能>,这里再介绍另一种实现方法. ...

  7. html js 动画效果,原生js html5 canvas 3D云动画效果

    特效描述:原生js html5canvas 3D云动画效果.3D云效果,叼炸天!可用鼠标控制方向!本地要localhost才能正常演示 代码结构 1. 引入JS 2. HTML代码 varying v ...

  8. 小清新版js打砖块游戏

    打砖块小游戏 A键发射小球开始游戏: 使用左右方向键,进行移动: 游戏结束时按A键重置游戏: S键暂停游戏: 通关后按N键进入下一关 游戏效果预览 写个HTML页面 通用CSS样式就不赘述了,主要是j ...

  9. 听说你想手机玩扫雷?原生JS扫雷游戏

    运行效果 操作方法 单击绿色环形按钮即可开局,用任何工具首次点击雷区不会出现游戏失败情况: 点击左侧图标选择工具,选择不同工具点击雷区效果不同: 红旗图标为windows扫雷右击,普通箭头图标为win ...

最新文章

  1. 【XSY2719】prime 莫比乌斯反演
  2. 在區塊鏈上建立可更新的智慧合約(一)
  3. MySQL timestamp的默认值怎么设置?
  4. Swift中switch比较元组类型
  5. 前端学习(1325):await关键字
  6. opencv 性能测试
  7. unity3d-ngui UIScrollView 滚动方向与滚轮相反
  8. 数据结构折半查找例题_山东2011专升本计算机专业数据结构练习题 - 图文
  9. apipost自动化测试工具
  10. 一次关于聚合根的激烈讨论
  11. 边缘计算是什么?边缘计算系统的组成及概念
  12. 苹果公司的电脑产品及其历史
  13. word恢复默认样式
  14. php ajax 考试倒计时,基于Ajax技术实现考试倒计时并自动提交试卷
  15. html提取excel指定单元格数据,怎样从很多的表格中提取指定单元格数据
  16. jquery发送put请求_通过 Ajax 发送 PUT、DELETE 请求的两种实现方式
  17. 企业电子邮件系统全局地址簿管理及使用方法介绍
  18. 云效一站式DevOps平台
  19. android烧录镜像,android 烧录image镜像
  20. 桥梁远景图微型计算机教案,小学六年级语文《桥梁远景图》教案模板

热门文章

  1. WinSCP下载安装及使用
  2. 高清和网络电视是数字电视的希望
  3. ChatGPT 爆火,社交应用如何 Get 新技能
  4. C++运动会分数统计系统
  5. 元宇宙营业厅,数字技术融合,赋能实体经济
  6. 关于买房提前还款问题
  7. c语言 函数计算0869,c语言编程- 微积分程序
  8. Onedrive如何申请免费的学生1T空间以及查看剩余空间大小
  9. 魔兽世界az端和TC端有什么区别 Mangos,TC,SW,AZ,AC的关系
  10. 核桃编程python下载_核桃编程for Mac