js扫雷游戏

这里是用js面向对象写的一个扫雷小游戏。

完整代码如下: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #mine{
            margin: 50px auto;
        }
        .level{
            text-align: center;
            margin-bottom: 10px;
        }
        .level button{
            padding: 5px 15px;
            background-color: #02a4ad;
            border: none;
            color: #fff;
            border-radius: 3px;
            outline: none;
            cursor: pointer;
        }
        .level button .active{
            background-color: #00abff;
        }
        .info{
            margin-top: 10px;
            text-align: center;
        }
        table{
            border-spacing: 1px;
            background-color: #929196;
            margin: 0 auto;
        }
        td{
            padding: 0;
            width: 20px;
            height: 20px;
            background-color: #ccc;
            border: 2px solid;
            border-color: #fff #a1a1a1 #a1a1a1 #fff;
            text-align: center;
            line-height: 20px;
            font-weight: bold;
        }
        .mine{
            background: #d9d9d9 url(./img/zhadan\(1\).png) no-repeat center;
            background-size: cover;
        }
        .flag{
            background: #ccc url(./img/qizi.png);
            background-size: cover;
        }
        td.zero{
            border-color: #d9d9d9;
            background: #d9d9d9;
        }
        td.one{ 
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #0332fe;
        }
        td.two{
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #019f02;
        }
        td.three{
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #ff2600;
        }
        td.four{
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #93208f;
        }
        td.five{
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #ff7f29;
        }
        td.six{
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #ff3fff;
        }
        td.seven{
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #3fffbf;
        }
        td.eight{
            border-color: #d9d9d9;
            background-color: #d9d9d9;
            color: #22ee0f;
        }
    </style>
</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>
</body>
<script>
    // 面向对象

    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++){
                // this.squares[i][j]=
                // n++;
                // 取一个方块在数组里的数据要使用行与列的形式去取,找方块周围的时候要用坐标的形式去取,行与列的形式跟坐标的形式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};
                }
            }

        }

        

        console.log(this.squares);
        // this.randomNum();
        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;
                // }
               

                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]];
            // console.log(curSquare);
            var cl = ['zero','one','two','three','four','five','six','seven','eight'];

            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.找四周(如果四周不为0,那就显示到这里,不需要再找了)
                                        1.显示自己
                                        2.找四周(如果四周不为0,那就显示到这里,不需要再找了)
                    */ 


                    obj.innerHTML = "";//如果数字为0不显示
                    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";
        }
    }

    // 上边button的功能
    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();

    // console.log(mine.getAround(mine.squares[0][0]));

</script>
</html>

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恬歆羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值