JS实现扫雷游戏

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

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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值