js+canvas扫雷小游戏

思路要点:

1. 随机地雷放到一个二维数组中;

2. 每一个格子要统计周围有几颗雷;

3. 每一个格子是否处于打开状态,用于判断是否赢得游戏;

4. 如果点击到周围没有雷的地方,把周围的打开;

具体的见代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			*{padding: 0;margin: 0;}
			canvas{margin: 0 auto;display: block;}
			.btns{margin: 0 auto;text-align: center;padding: 10px 0;}
		</style>
	</head>
	<body>
		<canvas id="mineMap"></canvas>
		<div class="btns">
			<button id="playAgain">再来一局</button>
		</div>
		
		<script src="mineClearance.js" type="text/javascript" charset="utf-8"></script>
		<script type="text/javascript">
			
			var game = new MineClearance("mineMap", 15, 0.15);
			var restart = document.getElementById("playAgain");
			restart.onclick = function (){
				game.resetData();
			}
		</script>
	</body>
</html>

  

class MineClearance{
	constructor(canvasId, rowCount, mineRate){
		this.rowCount = rowCount || 10;
		this.mineRate = mineRate || 0.1; // 地雷所占的百分比
		this.canvasId = canvasId;
		this.resetData();
	}
	
	// 重置数据
	resetData(){
		this.mines = []; // 所有地雷的数组
		this.mineCount = 0; // 地雷总数量,由地雷百分比算出
		// this.mineRate = 0.15; // 地雷所占的百分比
		this.minePositions = []; // 所有地雷的坐标
		this.mineTip = []; // 地雷的提示数组
		this.openStatus = []; // 所有位置的打开状态
		this.mineFlag = [];
          this.gameOver = false; this.cellWidth = 0; this.initMines(); this.initCanvas(); } // 初始化canvas initCanvas(){ var width = document.documentElement.clientWidth ||document.body.clientWidth; var height = document.documentElement.clientHeight || document.body.clientHeight; var minWidth = Math.min(width, (height - 50)); this.cellWidth = Math.floor(minWidth / this.rowCount); this.canvas = document.getElementById(this.canvasId); this.ctx = this.canvas.getContext("2d"); this.canvas.width = this.cellWidth * this.rowCount; this.canvas.height = this.cellWidth * this.rowCount; this.ctx.fillStyle = "yellow"; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.beginPath(); for(var i = 0; i <= this.rowCount; i ++){ this.ctx.moveTo(i * this.cellWidth, 0); this.ctx.lineTo(i * this.cellWidth, this.rowCount * this.cellWidth); } for(var i = 0; i <= this.rowCount; i ++){ this.ctx.moveTo(0, i * this.cellWidth); this.ctx.lineTo(this.rowCount * this.cellWidth, i * this.cellWidth); } this.ctx.strokeStyle = '#e73480'; this.ctx.stroke(); // this.ctx.closePath(); this.bindEvent(); } // 初始化地雷 initMines(){ this.mines = []; for(var i = 0; i < this.rowCount; i ++){ this.mines[i] = []; for(var j = 0; j < this.rowCount; j ++){ this.mines[i][j] = 0; } } // 随机地雷坐标 this.mineCount = parseInt(this.rowCount * this.rowCount * this.mineRate); var minePositions = []; console.time(); while(this.mineCount){ var x = parseInt(Math.random() * this.rowCount); var y = parseInt(Math.random() * this.rowCount); if(minePositions.indexOf(x + "," + y) == -1){ minePositions.push(x + "," + y); this.mineCount --; } } console.timeEnd(); this.minePositions = minePositions; // 地雷按号入座 for(var i = 0; i < this.minePositions.length; i ++){ var p = this.minePositions[i].split(","); this.mines[p[0]][p[1]] = 1; } console.log(this.mines); // 统计数组 var countArr = []; for(var i = 0; i < this.mines.length; i ++){ countArr[i] = []; for(var j = 0; j < this.mines[i].length; j ++){ var sum = 0; for(var ii = -1; ii <= 1; ii ++){ for(var jj = -1; jj <= 1; jj ++){ if(ii == 0 && jj == 0){ continue; } if(this.mines[i + ii] && this.mines[i + ii][j + jj]){ sum += this.mines[i + ii][j + jj]; } } } if(this.mines[i][j] == 1){ countArr[i][j] = 9; // 雷 此处用9代表地雷,反正周围有9个雷的话说明你必踩雷了,这里是为了数组输出时显示整齐 }else{ countArr[i][j] = sum; } } } this.mineTip = countArr; console.log(this.mineTip) // 每个格子的打开情况 for(var i = 0; i < this.rowCount; i ++){ this.openStatus[i] = []; for(var j = 0; j < this.rowCount; j ++){ this.openStatus[i][j] = false; } } // 标记数组(插旗情况) for(var i = 0; i < this.rowCount; i ++){ this.mineFlag[i] = []; for(var j = 0; j < this.rowCount; j ++){ this.mineFlag[i][j] = false; } } } // 绑定事件 bindEvent(){ var that = this; document.body.oncontextmenu = function (){ return false; } this.canvas.onmousedown = function(evt){ var e = evt || window.event; // console.log(this.getBoundingClientRect().left,e.clientX,that.cellWidth); // x,y与数组中的位置对应位置,请注意 var x = Math.floor((e.clientX - this.getBoundingClientRect().left) / that.cellWidth); var y = Math.floor((e.clientY - this.getBoundingClientRect().top) / that.cellWidth); console.log(x,y) if(e.which == 3){ // 1左键 2滚轮 3右键 // 插旗或取消插旗 that.changeFlag(x,y); }else if(e.which == 1){ // 打开格子 that.openCell(x, y); } } } // 画一个地雷 drawOneMine(x,y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); // 写对应的数字 this.ctx.font = `${this.cellWidth*0.75}px 方正舒体`; // 隶书 方正舒体 this.ctx.fillStyle = "red"; this.ctx.textBaseline = "middle"; this.ctx.textAlign = "center"; this.ctx.fillText("雷", xx + this.cellWidth / 2, yy + this.cellWidth / 2); this.drawBorder(x,y); } // 画雷区标记 drawFlag(x, y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); // 写对应的数字 this.ctx.font = `${this.cellWidth*0.75}px 方正舒体`; // 隶书 方正舒体 this.ctx.fillStyle = "blue"; this.ctx.textBaseline = "middle"; this.ctx.textAlign = "center"; this.ctx.fillText("旗", xx + this.cellWidth / 2, yy + this.cellWidth / 2); this.drawBorder(x,y); } // 取消雷区标记 cancelFlag(x, y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.fillStyle = "yellow"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); this.drawBorder(x,y); } // 插旗或取消插旗 changeFlag(x,y){ // 更改数据 if(this.mineFlag[x][y]){ console.log("取消插旗"); this.mineFlag[x][y] = false; this.openStatus[x][y] = false; this.cancelFlag(x, y);// 渲染canvas }else{ console.log("插旗"); this.mineFlag[x][y] = true; this.openStatus[x][y] = true; this.drawFlag(x, y);// 渲染canvas } } // 打开一个格子 openCell(x, y){ if(this.gameOver){ return; } if(!this.openStatus[x] || typeof this.openStatus[x][y] !== "boolean"){ return; } if(this.openStatus[x][y]){ console.warn("此位置已打开"); return; }else{ this.openStatus[x][y] = true; } var xx = this.cellWidth * x; var yy = this.cellWidth * y; // console.log(x,y,xx,yy) if(!this.mines[x][y]){ // 空位置 if(this.mineTip[x][y]){ // 有数字的位置 // this.ctx.clearRect(xx, yy, xx + this.cellWidth, yy + this.cellWidth); this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); // 写对应的数字 this.ctx.font = `${this.cellWidth*0.75}px 方正舒体`; // 隶书 方正舒体 this.ctx.fillStyle = "#e73480"; this.ctx.textBaseline = "middle"; this.ctx.textAlign = "center"; this.ctx.fillText(this.mineTip[x][y], xx + this.cellWidth / 2, yy + this.cellWidth / 2); this.drawBorder(x,y); this.isWin(); }else{ // 无数字的位置 console.log("周围无雷"); this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); this.drawBorder(x,y); // this.openCell(x - 1, y - 1); // 左上 this.openCell(x - 1, y); // 左 // this.openCell(x - 1, y + 1); // 左下 this.openCell(x, y - 1); // 上 this.openCell(x, y + 1); // 下 // this.openCell(x + 1, y - 1); // 右上 this.openCell(x + 1, y); // 右 // this.openCell(x + 1, y + 1); // 右下 } }else{ // 踩地雷了 console.log("gameOver"); this.gameOver = true; for(var i = 0, len = this.mines.length; i < len; i++){ for(var j = 0, jlen = this.mines[i].length; j < jlen; j++){ if(this.mines[i][j]){ this.drawOneMine(i,j); } } } this.toast("game over"); // alert("game over"); } } // 画一格格子的边框 drawBorder(x,y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.moveTo(xx, yy); this.ctx.lineTo(xx + this.cellWidth, yy); this.ctx.lineTo(xx + this.cellWidth, yy + this.cellWidth); this.ctx.lineTo(xx, yy + this.cellWidth); this.ctx.strokeStyle = "#e73480"; this.ctx.stroke(); } // 判断赢 isWin(){ var openCount = 0; this.openStatus.reduce(function (pre, cur){ cur.reduce(function(pre1,cur1){ if(cur1){ openCount ++; } },0); },0); // console.log(openCount); if(this.rowCount * this.rowCount - this.mineCount == openCount){ this.toast("恭喜过关"); } } toast(text){ setTimeout(function(){ alert(text); },30); } // 数组乱序 disorder(arr){ } }

  

猜你喜欢

转载自www.cnblogs.com/zhaodesheng/p/10485050.html