您的位置:首页 > Web前端 > JavaScript

JS实现扫雷游戏

2020-02-03 20:03 786 查看

跟着渡一教育视频做的扫雷游戏,感觉还有些不足,之后改进

html代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="css/index.css"/>
<title></title>
</head>
<body>
<div id="mine">
<div class="level">
<button class="active">初级</button>
<button>中级</button>
<button>高级</button>
<button>重新开始</button>
</div>
<div class="gameBox">

</div>
<div class="info">
剩余雷数:<span class="mineNum"></span>
</div>
</div>
<script src="js/index.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>

css代码:

#mine {
margin: 50px auto;
}

.level {
text-align: center;
margin-bottom: 10px;
}
.level button {
padding: 5px 15px;
background: #02a4ad;
border: none;
color: #fff;
border-radius: 3px;
outline: none;
cursor: pointer;
}
.level button.active {
background: #00abff;
}

table {
border-spacing: 1px;
background: #929196;
margin: 0 auto;
}
td {
padding: 0;
width: 20px;
height: 20px;
background: #ccc;
border: 2px solid;
border-color: #fff #a1a1a1 #A1A1A1 #fff;

/* font-size: 12px; */
line-height: 20px;
text-align: center;
font-weight: bold;
}

.info {
margin-top: 10px;
text-align: center;
}

.mine {
background: #d9d9d9 url(../img/mine.png) no-repeat center;
background-size: cover;
}
.flag {
background: #ccc url(../img/flag.png) no-repeat center;
background-size: cover;
}

/* 数字颜色 */
td.zero {
border-color: #d9d9d9;
background: #d9d9d9;
}
td.one {
border-color: #d9d9d9;
background: #d9d9d9;
color: #0332fe;
}
td.two {
border-color: #d9d9d9;
background: #d9d9d9;
color: #019f02;
}
td.three {
border-color: #d9d9d9;
background: #d9d9d9;
color: #ff2000;
}
td.four {
border-color: #d9d9d9;
background: #d9d9d9;
color: #93208f;
}
td.five {
border-color: #d9d9d9;
background: #d9d9d9;
color: #ff7f29;
}
td.six {
border-color: #d9d9d9;
background: #d9d9d9;
color: #ff3fff;
}
td.seven {
border-color: #d9d9d9;
background: #d9d9d9;
color: #3fffbf;
}
td.eight {
border-color: #d9d9d9;
background: #d9d9d9;
color: #22ee0f;
}

js代码:

function Mine(tr, td, mineNum){
this.tr = tr;   //行数
this.td = td;    //列数
this.mineNum = mineNum;    //雷的数量

this.squares = [];   //存储所有方块的信息,它是一个二维数组,按行与列的顺序排放。存取都使用行列形式
this.tds = [];    //存储所有单元格的DOM
this.surplusMine = mineNum;  //剩余雷的数量
this.allRight = false;   //右击标的小红旗是否全是雷。用来判断用户是否游戏成功

this.parent = document.querySelector('.gameBox');
}

//生成N个不重复的数字
Mine.prototype.randomNum = function(){
var square = new Array(this.tr*this.td);    //生成一个空数组,但是有长度,长度为格子的总数
for(var i=0;i<square.length;i++){
square[i]=i;
}
square.sort(function(){return 0.5-Math.random()});
return square.slice(0,this.mineNum);
}

Mine.prototype.init=function(){
var rn = this.randomNum();    //雷在格子里的位置
var n = 0;    //用来找格子对应的索引
for (var i = 0; i < this.tr; i++){
this.squares[i] = [];
for(var j = 0; j < this.td; j++){

//取一个方块在数组里的数据要使用行与列的形式去取。找方块周围的方块的时候要用坐标的形式去取。行与列的形式跟坐标的形式x,y是刚好相反的
if(rn.indexOf(n) != -1){
//如果这个条件成立,说明现在循环到的这个索引在雷的数组里找到了,那就表示这个索引对应的是雷。
this.squares[i][j] = {type:'mine',x:j,y:i};
} else {
this.squares[i][j] = {type:'number', x:j, y:i, value:0};
}
n++;
}

}
// console.log(this.squares);
this.updateNum();
this.createDom();
this.parent.oncontextmenu = function(){
return false;
};

//剩余雷数
this.mineNumDom = document.querySelector('.mineNum');
this.mineNumDom.innerHTML = this.surplusMine;
};

//创建表格
Mine.prototype.createDom = function(){
var This = this;
var table = document.createElement('table');

for (var i = 0; i < this.tr; i++){    //行
var domTr = document.createElement('tr');
this.tds[i] = [];

for(var j = 0; j < this.td; j++){
var domTd = document.createElement('td');
// domTd.innerHTML = 0;

domTd.pos = [i,j];    //把格子相对应的行与列存到格子上,为了下面通过这个值去数组里取到对应的数据
domTd.onmousedown = function(){
This.play(event,this);      //This指的是实例对象,this指的是点击的那个td
};
this.tds[i][j] = domTd;    //把所有创建的td添加到数组当中

// if(this.squares[i][j].type == 'mine'){
// 	domTd.className = 'mine';
// }
// if(this.squares[i][j].type == 'number'){
// 	domTd.innerHTML = this.squares[i][j].value;
// }

// domTd.oncontextmenu = function(){
// 	return false;
// };
domTr.appendChild(domTd);
}
table.appendChild(domTr);
}

this.parent.innerHTML = '';
this.parent.appendChild(table);
}

//找某个方格周围的8个方格
Mine.prototype.getAround = function(square){
var x = square.x;
var y = square.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.squares[j][i].type=='mine'   //周围的格子是个雷
){
continue;
}
result.push([j,i]);
}
}

return result;
}

//更新所有数字
Mine.prototype.updateNum = function(){
for(var i = 0; i < this.tr; i++){
for (var j = 0; j < this.td; j++){
if(this.squares[i][j].type == 'number'){
continue;
}
var num = this.getAround(this.squares[i][j]);   //获取到一个雷周围的数字
// console.log(num);

for(var k=0; k<num.length; k++){
this.squares[num[k][0]][num[k][1]].value += 1;
}
}
}
// console.log(this.squares);
}

Mine.prototype.play = function(ev, obj){
var This = this;
if(ev.which==1 && obj.className != 'flag'){
//点击的是左键
// console.log(obj);
var curSquare = this.squares[obj.pos[0]][obj.pos[1]];
var cl = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight'];

if(curSquare.type == 'number'){
//用户点到的是数字
obj.innerHTML = curSquare.value;
obj.className = cl[curSquare.value];

if(curSquare.value == 0){
/*用户点到了0
1.显示自己
2.找四周
1.显示四周,(如果四周的值不为0,就显示到这里,不需要再找了)
2.如果值为0
1.显示自己
2.找四周,(如果四周的值不为0,就显示到这里,不需要再找了)
*/
obj.innerHTML = '';    //如果是0,则不显示

function getAllZero(square) {
var around = This.getAround(square);   //找到了周围n个格子

for(var i = 0; i <around.length; i++){
// around[i]=[0,0];
var x = around[i][0];  //行
var y = around[i][1];    //列

This.tds[x][y].className = cl[This.squares[x][y].value];

if(This.squares[x][y].value == 0){
// 如果以某个格子为中心找到的格子值为0,那就需要继续调用函数(递归)
if(!This.tds[x][y].check){
//给对应的td添加一个属性,这条属性用于决定这个格子有没有被找过。如果被找过的话,他的值就为true,下一次就不会找了
This.tds[x][y].check = true;
getAllZero(This.squares[x][y]);
}

} else {
//如果以某个格子为中心找到的四周的格子不为0,那就把人家的数字显示出来
This.tds[x][y].innerHTML = This.squares[x][y].value;
}
}

}
getAllZero(curSquare);
}
} else {
//用户点到的是雷
this.gameOver(obj);
}
}

//用户点击的是右键
if(ev.which == 3){
//如果右击的是一个数字,那就不能点击
if(obj.className && obj.className != 'flag'){
return;
}
obj.className = obj.className == 'flag'?'':'flag';  //切换class

if(this.squares[obj.pos[0]][obj.pos[1]].type == 'mine'){
this.allRight = true;   //用户标的小红旗都是雷
} else {
this.allRight = false;
}

if(obj.className == 'flag'){
this.mineNumDom.innerHTML = --this.surplusMine;
}else {
this.mineNumDom.innerHTML = ++this.surplusMine;
}

if(this.surplusMine == 0){
//剩余的雷数为0,表示用户已经标完小红旗,这时候要判断游戏是成功还是失败
if(this.allRight){
alert('恭喜你,游戏通过');
} else {
alert('游戏失败');
this.gameOver();
}
}
}
};

//游戏失败函数
Mine.prototype.gameOver = function(clickTd){
/*
1.显示所有的雷
2.取消所有格子的点击事件
3.给点中的那个雷标上一个红
*/
for(var i = 0; i < this.tr; i++){
for(var j = 0; j < this.td; j++){
if(this.squares[i][j].type == 'mine'){
this.tds[i][j].className = 'mine';
}

this.tds[i][j].onmousedown = null;
}
}
if(clickTd){
clickTd.style.backgroundColor = '#f00';
}
}

//上边botton的功能
var btns = document.querySelectorAll('.level button');
var mine = null;    //用来存储生成的实例
var ln = 0;   //用来处理当前选中的状态
var arr = [[9,9,10],[16,16,40],[28,28,99]];   //不同级别的行数列数雷数

for(let i = 0; i < btns.length-1; i ++){
btns[i].onclick = function(){
btns[ln].className = '';
this.className = 'active';

// mine = new Mine(arr[i][0],arr[i][1]);
mine = new Mine(...arr[i]);
mine.init();

ln = i;
}
}
btns[0].onclick();   //初始化
btns[3].onclick = function(){
mine.init();
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
玉子不吃辣椒 发布了12 篇原创文章 · 获赞 0 · 访问量 293 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: