原生JS实现简易扫雷游戏
Posted 听雪拨弦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生JS实现简易扫雷游戏相关的知识,希望对你有一定的参考价值。
注:使用了Font Awesome 字体图标库,使用前请下载引入(下载地址)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>扫雷小游戏2.2</title>
<link rel="stylesheet" href="./css/font-awesome.min.css">
<style>
* {
user-select: none;
}
.mineBox {
width: 900px;
height: 600px;
margin: 0 auto;
border: 3px solid gray;
position: relative;
color: black;
}
.red {
font-size: 22px;
color: #B22222;
}
.black {
font-size: 22px;
color: black;
}
.difficulty {
width: 900px;
text-align: center;
margin: 0 auto 15px;
}
button {
width: 60px;
height: 25px;
}
.info {
position: fixed;
top: 100px;
left: 190px;
}
input {
width: 60px;
height: 40px;
margin-left: 2px;
margin-top: 10px;
text-align: center;
font-weight: bold;
font-size: 18px;
}
#times {
font-size: 16px;
font-weight: none;
}
.success {
position: absolute;
width: 120px;
height: 40px;
text-align: center;
line-height: 40px;
top: -160px;
bottom: 0;
left: 0;
right: 0;
margin: auto;
background: rgba(255, 255, 255, 0.4);
z-index: 1000;
border-radius: 25px;
display: none;
}
</style>
</head>
<body>
<div class="success">
恭喜通关
</div>
<div class="difficulty">
<b>难度选择:</b> <b style="color: #FF00FF">Lunatic</b><br>
<button class="Easy">Easy</button>
<button class="Normal">Normal</button>
<button class="Hard">Hard</button>
<button class="Lunatic">Lunatic</button>
<button class="Extra">Extra</button>
</div>
<div class="mineBox"></div>
<div class="info">
地雷:
<input type="text" readonly id="txtB"><br>
旗帜:
<input type="text" readonly id="txtF"><br>
时间:
<input type="text" readonly id="times" value="0"><br>
</div>
<script>
class Mining {
constructor() {
// 获取存放小盒子的节点
this.mineBox = document.getElementsByClassName('mineBox')[0];
// 定义一个用来存放雷div的下标的数组
this.arr = [];
// 获取存放按钮的节点
this.btnList = document.querySelectorAll('.difficulty button');
// 获取显示难度的节点
this.diff = document.getElementsByTagName('b')[1];
// 获取显示雷数量的节点
this.txtBomb = document.getElementById('txtB');
// 获取显示旗子数量的节点
this.txtFlag = document.getElementById('txtF');
// 获取显示时间的节点
this.txtTime = document.getElementById('times');
// 定义小盒子的默认宽高
this.sDivW = 30;
this.sDivH = 30;
// 定义雷的默认数量
this.bombSum = 120;
// 定义旗子的默认数量
this.flagSum = this.bombSum;
// 将雷和旗子的数量显示到input框内
this.txtBomb.value = this.bombSum;
this.txtFlag.value = this.flagSum;
// 设置标记正确后的变量
this.success = 0;
// 设置游戏结束状态
this.endGame = false;
// 定义计时器&计时器状态
this.times = '';
this.timeStatus = true;
// 默认执行一次
this.init();
// 给按钮绑定点击事件
this.btnList.forEach(v => {
v.addEventListener('click', () => {
switch (v.className) {
case 'Easy':
this.clear();
this.mineBox.style.width = '500px';
this.mineBox.style.height = '500px';
this.sDivW = 50;
this.sDivH = 50;
this.bombSum = 10;
this.flagSum = this.bombSum;
this.txtBomb.value = this.bombSum;
this.txtFlag.value = this.flagSum;
this.init();
this.diff.innerText = 'Easy';
this.diff.style.color = '#00FF00';
break;
case 'Normal':
this.clear();
this.mineBox.style.width = '600px';
this.mineBox.style.height = '600px';
this.sDivW = 50;
this.sDivH = 50;
this.bombSum = 15;
this.flagSum = this.bombSum;
this.txtBomb.value = this.bombSum;
this.txtFlag.value = this.flagSum;
this.init();
this.diff.innerText = 'Normal';
this.diff.style.color = '#4169E1';
break;
case 'Hard':
this.clear();
this.mineBox.style.width = '800px';
this.mineBox.style.height = '600px';
this.sDivW = 50;
this.sDivH = 50;
this.bombSum = 30;
this.flagSum = this.bombSum;
this.txtBomb.value = this.bombSum;
this.txtFlag.value = this.flagSum;
this.init();
this.diff.innerText = 'Hard';
this.diff.style.color = '#FF0000';
break;
case 'Lunatic':
this.clear();
this.mineBox.style.width = '900px';
this.mineBox.style.height = '600px';
this.sDivW = 30;
this.sDivH = 30;
this.bombSum = 120;
this.flagSum = this.bombSum;
this.txtBomb.value = this.bombSum;
this.txtFlag.value = this.flagSum;
this.init();
this.diff.innerText = 'Lunatic';
this.diff.style.color = '#FF00FF';
break;
case 'Extra':
this.clear();
this.mineBox.style.width = '900px';
this.mineBox.style.height = '600px';
this.sDivW = 30;
this.sDivH = 30;
this.bombSum = 180;
this.flagSum = this.bombSum;
this.txtBomb.value = this.bombSum;
this.txtFlag.value = this.flagSum;
this.init();
this.diff.innerText = 'Extra';
this.diff.style.color = '#A020F0';
break;
default:
throw console.error('报错了...');
break;
}
})
});
}
clear() {
//清空大盒子
this.mineBox.innerHTML = '';
//清空存放div的数组
this.arr = [];
//重置时间
this.txtTime.value = '0';
//清除定时器
clearInterval(this.times);
//设置定时器状态
this.timeStatus = true;
// 设置游戏结束状态
this.endGame = false;
//清除标记正确后的变量
this.succefss = 0;
}
init() {
// 动态创建小div放在box里面
this.create(this.sDivW, this.sDivH);
// 标记地雷
this.markBomb();
// 点击小盒子
this.blockClick();
}
create(mineW, mineH) {
this.mineN = this.mineBox.clientWidth * this.mineBox.clientHeight / (mineW * mineH);
this.mineCol = this.mineBox.clientWidth / mineW;
this.mineRow = this.mineBox.clientHeight / mineH;
// 定义一个数组,将周围div的下标存起来
this.arr2 = [-(this.mineCol + 1), -this.mineCol, -(this.mineCol - 1), -1, 1, this.mineCol - 1, this.mineCol, (this.mineCol + 1)];
for (let i = 0; i < this.mineN; i++) {
let block = document.createElement('div');
setStyle(block, {
width: mineW - 2 + "px",
height: mineH - 2 + "px",
backgroundColor: "rgb(141,162,155)",
border: "1px solid #fff",
position: "absolute",
left: (i % this.mineCol) * mineW + "px",
top: parseInt(i / this.mineCol) * mineH + "px",
textAlign: "center",
lineHeight: mineH + "px"
})
this.mineBox.appendChild(block);
//判断是不是雷
block.mine = false;
//判断小方块是否被打开
block.show = false;
//判断插旗状态
block.status = 0;
}
}
markBomb() {
// 标记雷
for (let i = 0; i < this.bombSum; i++) {
// 获取随机下标
let index = Math.floor(Math.random() * this.mineN)
// 判断数组中是否已经有了这个下标
if (this.arr.indexOf(index) < 0) this.arr.push(index); else i--;
}
for (let i = 0; i < this.arr.length; i++) {
this.mineBox.children[this.arr[i]].mine = true
}
for (var i = 0; i < this.mineBox.children.length; i++) {
// 如果当前这个div是雷就不统计了
if (this.mineBox.children[i].mine) {
continue;
}
// this.mineBox.children[i] // 每个div
// 查看当前div周围的所有div
// 定义周围雷数量的变量
let bombN = 0
for (var j = 0; j < this.arr2.length; j++) {
// 考虑最上面一行 - 不能-(this.mineCol+1) 不能-this.mineCol 不能-(this.mineCol-1)
if (i < this.mineCol && (this.arr2[j] === -(this.mineCol + 1) || this.arr2[j] === -this.mineCol || this.arr2[j] === -(this.mineCol - 1))) {
continue;
}
// // 最左边一行过滤掉
if (i % this.mineCol === 0 && (this.arr2[j] === -(this.mineCol + 1) || this.arr2[j] === -1 || this.arr2[j] === (this.mineCol - 1))) {
continue;
}
// 最下面一行
if (parseInt(i / this.mineCol) === this.mineRow - 1 && (this.arr2[j] === (this.mineCol - 1) || this.arr2[j] === this.mineCol || this.arr2[j] === (this.mineCol + 1))) {
continue;
}
// 最右边一行
if (i % this.mineCol === this.mineCol - 1 && (this.arr2[j] === -(this.mineCol - 1) || this.arr2[j] === 1 || this.arr2[j] === (this.mineCol + 1))) {
continue;
}
if (this.mineBox.children[i + (this.arr2[j])].mine) {
bombN++
}
}
// 将雷的数量放在div中
this.mineBox.children[i].bombN = bombN
}
}
blockClick() {
for (let i = 0; i < this.mineBox.children.length; i++) {
this.mineBox.children[i].index = i;
let that = this;
this.mineBox.children[i].onclick = function () {
//如果计时器未开启 则开启计时器 (仅在第一次点击时开启定时器)
if (that.timeStatus) {
that.txtTime.value = '1';
that.timer();
that.timeStatus = false;
}
if (this.mine) {
// 如果点击到雷了
for (let j = 0; j < that.mineBox.children.length; j++) {
//清除计时器
clearInterval(that.times);
// 设置游戏结束状态
that.endGame = true;
// 给所有不是雷的div设置内容显示,雷的数量
that.mineBox.children[j].innerText = that.mineBox.children[j].bombN ? that.mineBox.children[j].bombN : '';
that.mineBox.children[j].style.backgroundColor = 'rgb(210,222,238)';
}
// 将所有是雷的div设置为红色
for (let j = 0; j < that.arr.length; j++) {
that.mineBox.children[that.arr[j]].style.backgroundColor = 'red';
that.mineBox.children[that.arr[j]].innerHTML = '<i class="fa fa-bomb black">';
}
} else {
that.openAround(this.index)
}
}
this.mineBox.children[i].oncontextmenu =
function () {
// 如果小盒子已经是打开的状态 则跳出函数
if (this.show) return false;
// 如果游戏已经结束了 则跳出函数
if (that.endGame) return false;
if (this.status == 0) {
this.innerHTML = '<i class="fa fa-flag red">';
this.status = 1;
that.flagSum--;
that.txtFlag.value = that.flagSum;
if (this.mine) {
that.success++;
if (that.success == that.bombSum) {
//清除计时器
clearInterval(that.times);
//设置通关状态
that.endGame = true;
//显示通关信息
document.getElementsByClassName('success')[0].style.display = 'block';
//设置延时2秒后关闭
setTimeout(() => {
document.getElementsByClassName('success')[0].style.display = 'none';
}, 2000);
}
}
return false;
}
if (this.status == 1) {
this.innerHTML = '<i class="fa fa-question black">';
this.status = 2;
return false;
}
if (this.status) {
if (this.mine) {
that.success--;
}
this.innerHTML = '';
this.status = 0;
that.flagSum++;
that.txtFlag.value = that.flagSum;
return false;
}
}
}
}
// 打开周围div的递归函数
openAround(index) {
this.mineBox.children[index].innerText = this.mineBox.children[index].bombN
this.mineBox.children[index].style.backgroundColor = 'rgb(210,222,238)'
this.mineBox.children[index].show = true
if (this.mineBox.children[index].bombN === 0) {
this.mineBox.children[index].innerText = '';
for (let j = 0; j < this.arr2.length; j++) {
if (index < this.mineCol && (this.arr2[j] === -(this.mineCol + 1) || this.arr2[j] === -this.mineCol || this.arr2[j] === -(this.mineCol - 1))) {
continue;
}
// // 最左边一行过滤掉
if (index % this.mineCol === 0 && (this.arr2[j] === -(this.mineCol + 1) || this.arr2[j] === -1 || this.arr2[j] === (this.mineCol - 1))) {
continue;
}
// 最下面一行
if (parseInt(index / this.mineCol) === this.mineRow - 1 && (this.arr2[j] === (this.mineCol - 1) || this.arr2[j] === this.mineCol || this.arr2[j] === (this.mineCol + 1))) {
continue;
}
// 最右边一行
if (index % this.mineCol === this.mineCol - 1 && (this.arr2[j] === -(this.mineCol - 1) || this.arr2[j] === 1 || this.arr2[j] === (this.mineCol + 1))) {
continue;
}
if (this.mineBox.children[index + this.arr2[j]].show) {
continue
}
this.openAround(index + this.arr2[j])
}
}
}
// 设置计时器函数
timer() {
this.times = setInterval(() => {
this.txtTime.value = (this.txtTime.value - 0) + 1;
}, 1000);
}
}
new Mining;
//封装设置样式的方法
function setStyle(tag, styleObj) {
for (var attr in styleObj) {
tag.style[attr] = styleObj[attr];
}
}
</script>
</body>
</html>
以上是关于原生JS实现简易扫雷游戏的主要内容,如果未能解决你的问题,请参考以下文章