写扫雷游戏的思路:
1.动态生成一百个(可以更多)div块
2.左键点击事件(显示周围的地雷数、扩散算法)
3.右键点击事件(插旗与取消插旗、胜利事件)
多说一句:所谓的扩散就是当点击的元素显示的数字为0即周围没有雷时,又点击它周围显示的数为0的元素
直到有雷为止
因为这个游戏的逻辑有点杂,所以小编决定将整个代码贴出来,通过注释来讲解
源码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>原生JS&&扫雷游戏</title>
<style>
*{
padding: 0;
margin: 0;
}
.plat{
width: 100%;
height: 100%;
position: fixed; /*相对于界面的左上角进行绝对定位*/
top:0;
left: 0;
background-image: url("img/bg (2).jpg"); /*整个界面背景图*/
/*大家可以自选小编的图会在下面给出*/
background-size: 100% 100%;
}
.btn{
height: 140px;
width: 200px;
position: absolute;
right: 20px;
bottom: 10px;
background-image: url("img/startGame.png");
background-size: 100% 100%;
cursor: pointer;
}
.box{
height: 500px;
width: 500px;
transform: perspective(800px) rotateX(45deg); /*径深800px并绕X轴旋转45度*/
margin: 20px auto;
border-top: 1px solid #b25f27;
border-left: 1px solid #b25f27;
box-shadow: 5px 5px 5px rgb(0,0,0,0.3); /*css3属性调控阴影样式*/
background-color: #cccccc;
display: none; /*隐藏*/
}
.flag{
display: none;
position: absolute;
left: 50%;
top:50px;
margin-left: -100px;
height: 50px;
width: 200px;
color: #3C3C3C;
font-weight: bold;
font-size: 20px;
}
.alertbox{
display: none;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: rgba(0,0,0,0.2);
}
.alertimg{
background-size: 100% 100%;
width: 600px;
height: 400px;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom:0;
margin: auto;
border-radius: 5px; /*圆角*/
cursor: pointer;
}
.block{ /*动态生成的div块样式*/
width: 49px;
height: 49px;
border-right: 1px solid #b25f27;
border-bottom: 1px solid #b25f27;
background-image: url("img/cao.jpg");
float: left;
box-shadow: 0 0 4px #3C3C3C inset; /*内阴影*/
}
.show{
background-image: url("img/dilei.png"); /*地雷图*/
background-size: 100% 100%;
}
.num{ /*左键点击后div块的样式*/
background: #ecd0a1;
line-height: 49px;
font-weight: bold;
text-align: center;
}
.boxflag{
background-image: url("img/qi.jpg"); /*五星红旗图*/
background-size: 100% 100%;
}
</style>
</head>
<body>
<div class="plat">
<!--开始游戏的按钮块-->
<div class="btn" id="btn"></div>
<!--扫雷盘-->
<div class="box" id="box"></div>
<div class="flag" id="flag">
当前剩余雷数:
<span id="scroe">10</span>
</div>
<div class="alertbox" id="alertbox"> <!--当游戏失败或胜利时出现的提示块-->
<div class="alertimg" id="alertimg"></div>
</div>
</div>
<script>
var btn = document.getElementById('btn');
var box = document.getElementById('box');
var flag = document.getElementById('flag');
var alertbox = document.getElementById('alertbox');
var alertimg = document.getElementById('alertimg');
var scroe =document.getElementById('scroe');
var startGameBool = true;
var mineNum;
var mineOver;
var b; //承接生成的div块
var mine =[];
var L;
addEvent();
function addEvent() { //整合所有的触发事件
btn.onclick = function () {
if (startGameBool == true) { //只允许触发一次生成div块方法
box.style.display = 'block';
flag.style.display = 'block';
init();
startGameBool = false;
}
}
box.oncontextmenu = function () { //取消右键在扫雷区的默认事件
return false;
}
box.onmousedown = function (e) { //判断鼠标的左右键并分别执行不同事件
var event = e.target; //点击目标元素的源事件
if (e.which ==1) {
leftClick(event);
}
else if (e.which == 3) {
rightClick(event);
}
}
alertimg.onclick = function () { //当弹出胜利或失败的图片后点击图片刷新游戏让人可以玩一整夜
window.location.reload();
}
}
function init() { //动态生成div块函数
mineOver = 10;
mineNum = 10;
for (var i = 0;i < 10; i++) {
for (var j = 0; j < 10; j++) { //通过for的双重循环来动态生成100个div块
b = document.createElement('div');
b.classList.add('block'); //给生成的div块添加名为block的className
b.setAttribute('id',i+'-'+j); //有序的给生成的div块添加id名例如第二个的id为1-0 有序很重要!
box.appendChild(b); //添加元素
mine.push({mines:0}); //这个数组用来判断元素是否为雷
}
}
L = document.getElementsByClassName('block');
while (mineNum) { //当mineNum存在时
var numIndex = Math.floor(Math.random()*100);
if (mine[numIndex].mines ==0) { //当数组的值为1时表示这个元素是雷将不会再给其添加
//className即不会进入这个循环
L[numIndex].classList.add('Lei');
mine[numIndex].mines = 1;
mineNum--;
}
}
}
function leftClick(dom) { //鼠标左键触发函数
var Lei = document.getElementsByClassName('Lei');
if (dom && dom.classList.contains('Lei')) { //如果点击的包含Lei这个className
alertbox.style.display = 'block';
for (var i=0;i<Lei.length;i++){ //所有的雷都显示出来
Lei[i].classList.add('show');
}
setTimeout(function () { //隔500毫秒弹出失败的图片
alertimg.style.backgroundImage = 'url("img/gameOver.png")';
},500)
}
else {
var n = 0;
var posArr = dom && dom.getAttribute('id').split('-'); //返回不包含斜杠的两个id字符串
var posX = +posArr[0]; //通过隐式类型转换得到id的第一个数
var posY = +posArr[1]; //同上
dom && dom.classList.add('num');
for (var i=posX-1;i<=posX+1;i++) { //遍历被点击元素周围的八个元素
for (var j=posY-1;j<=posY+1;j++) {
var around = document.getElementById(i+'-'+j);
if (around && around.classList.contains('Lei')) {
n++;
}
}
}
if (dom.classList.contains('boxflag')) {
dom.classList.remove('boxflag');
} //点击到已被标记五星红旗的元素时移除它的className
dom && (dom.innerHTML = n);
//扩散算法即递归
if (n == 0) {
for (var i=posX-1;i<=posX+1;i++) {
for (var j = posY - 1; j <= posY + 1; j++) {
var nearBox = document.getElementById(i+'-'+j);
if (nearBox && nearBox.length != 0){ //如果周围有显示数为0的元素
if (!nearBox.classList.contains('check')) { //避免重复点击已被点击过的元素
nearBox.classList.add('check');
leftClick(nearBox);
}
}
}
}
}
}
}
function rightClick(dom) { //鼠标右键触发函数
if (dom && dom.classList.contains('num')) { //如果点击到了已经显示数字的元素则不触发
return;
}
dom && dom.classList.toggle('boxflag'); //插旗
if (dom.classList.contains('Lei') && dom.classList.contains('boxflag')) {
mineOver--;
}
if (dom.classList.contains('Lei') && !dom.classList.contains('boxflag')) {
mineOver++;
}
scroe.innerHTML = mineOver;
if (mineOver ==0) {
alertbox.style.display = 'block';
setTimeout(function () {
alertimg.style.backgroundImage = 'url("img/ssucces.jpg")';
},500)
}
}
</script>
</body>
</html>
图片资源:
百度网盘
大家复制粘贴代码时,记得更改图片的路径