JS扫雷小游戏(DOM (html+css+js))

html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="css/index.css">
</head>
<body>
    <div id="main">
        <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"></script>
</body>
</html>

css代码:

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

}
table{
    border-spacing: 1px;
    background-image: linear-gradient(to bottom right, #B3E5FC, #3644BE);
    margin: 0 auto;
}
td{
    padding: 0;
    width: 20px;
    height: 20px;
    background: rgba(255,255,255,0);
    border: 2px solid;
    border-color: #95CCF6 #3644BE #3644BE #95CCF6;
    text-align: center;
    line-height: 20px;
}
td.zero{
    border-color: #E1F5FE;
    background: #E1F5FE;
}
td.one{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #0332fe;
}
td.two{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #019f02;
}
td.three{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #ff2600;
}
td.four{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #93208f;
}
td.five{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #ff7f29;
}
td.six{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #ff3fff;
}
td.seven{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #3fffbf;
}
td.eight{
    border-color: #E1F5FE;
    background: #E1F5FE;
    color: #22ee0f;
}
.info{
    text-align: center;
    margin-top: 10px;
}
.mine {
    background: #E1F5FE url(../img/bg3.png) no-repeat center;
    background-size:cover;
}
.flag{
    background: #E3F2FD url(../img/bg2.png) no-repeat center;
    background-size:cover;
}

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;
    }
    // console.log(square);
    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;
            // if(this.squares[i][j].type == 'mine'){
            //     domTd.className= 'mine'
            // }
            // if(this.squares[i][j].type == 'number'){
            //     domTd.innerHTML = this.squares[i][j].value;
            // }
          

            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]);  // 获取到每一个雷周围的数字
            for(var k=0; k<num.length; k++){
                this.squares[num[k][0]][num[k][1]].value +=1;
            }
        }
    }
}

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

        console.log(curSquare);
        if(curSquare.type == 'number') {
            console.log('点到数字')
            obj.innerHTML = curSquare.value;
            obj.className = cl[curSquare.value];
            if(curSquare.value == 0){
               /*  
                当用户点到了数字0
                 1. 显示自己
                 2. 找四周
                    1. 显示四周,(如果四周的值不为0,那就显示到这里,不需要再找了)
                    2. 如果值为0
                        1. 显示自己
                        2. 找四周
                            。。。。。 递归
               */
                obj.innerHTML = '';
                function getAllZero(square) {
                    var around = This.getAround(square);   // 找到了周围的N个格子
                    for(var i =0; i<around.length; i++) {
                        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{
            // 点到雷
            // console.log('点到雷')
            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';
   }
}


// 菜单栏按钮功能
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]);
        mine.init();
        ln = i;
    }
}

btns[0].onclick();
btns[3].onclick = function() {
    mine.init();
}
// var mine = new Mine(28,28,99);
// mine.init();

图片素材:

在这里插入图片描述
在这里插入图片描述

效果图:

在这里插入图片描述
js扫雷小游戏在线演示(注意:试玩用pc端打开哦,移动端没写兼容。)

js扫雷小游戏源代码下载地址

js贪吃蛇小游戏链接
python小黄脸大战小游戏链接
vue高仿网易云音乐app

发布了69 篇原创文章 · 获赞 96 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_40693643/article/details/103009459