扫雷小游戏

写了一个小游戏,扫雷

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>扫雷</title>
    <link rel="stylesheet" href="game.css">
</head>

<body>
    <div class="main">
        <header class="header">
            <button>入门</button>
            <button>初级</button>
            <button>中级</button>
            <button>高级</button>
            <button>终极</button>
        </header>
        <div class="gameBox" id="gameBox"></div>
        <footer class="footer">剩余雷数量:<span id="surplusMine"></span>
        </footer>
    </div>
</body>
<script src="game.js"></script>

</html>

css文件

.main .header {
    text-align: center;
    margin: 20px auto;
}

.header button:hover{
    background: #00abff;
}

table{
    border-spacing: 1px;
    background: #929196;
    margin: 0 auto;
}

td{
    padding: 0;
    width: 20px;
    height: 20px;
    background: #ccc;
    border: 2px solid ;
    border-color: #fff #a1a1a1 #a1a1a1 #fff;
    text-align: center;
    line-height: 20px;
    font-weight: bold;
}

.main .gameBox table {
    border-spacing: 1px;
    background-color: rgb(170, 170, 170);
    text-align: center;
    margin: 20px auto;
}

.main .gameBox table td.mine {
    /* 游戏结束时显示 */
    border: none;
    background: url(./pang.png) no-repeat;
    background-size: 100% 100%;
    background-color: #e9e6e6;
    background-position: 2px 0;
}

.main .gameBox table td.targetMine {
    /* 游戏结束时显示,触发雷的单元格 */
    border: none;
    background: url(./pang.png) no-repeat;
    background-size: 100% 100%;
    background-color: #ff4b4b;
    background-position: 2px 0;
}

.main .gameBox table td.targetFlag {
    /* 右键标记方格时显示 */
    background: url(./flag.png) no-repeat;
    background-size: 90% 90%;
    background-position: 2px 0;
    background-color: #e9e6e6;
}

.main .gameBox table td {
    /* 单元格初始样式 */
    width: 20px;
    height: 20px;
    box-sizing: border-box;
    border: 2px solid;
    border-color: #eee #ccc #ccc #eee;
    background-color: #e9e6e6;
    font-size: 1px;
    font-weight: 800;
}

.gameBox table td.zero,
.gameBox table td.one,
.gameBox table td.two,
.gameBox table td.three,
.gameBox table td.four,
.gameBox table td.five,
.gameBox table td.six,
.gameBox table td.seven,
.gameBox table td.eight,
.gameBox table td.nine {
    border: none;
    background-color: rgb(211, 200, 200);
}


.gameBox table td.one {
    color: blue;
}

.gameBox table td.two {
    color: rgb(5, 93, 5);
}

.gameBox table td.three {
    color: #008c8c;
}

.gameBox table td.four {
    color: crimson;
}

.gameBox table td.five {
    color: rgb(228, 91, 0);
}

.gameBox table td.six {
    color: darkorange;
}

.gameBox table td.seven {
    color: rgb(193, 196, 50);
}

.gameBox table td.eight {
    color: pink;
}

.main .footer {
    text-align: center;
}

js文件

function Game(tr, td, mineNum) {
    this.td = td;
    this.tr = tr;
    this.mineNum = mineNum; //存储预设或设定的炸弹总数,用于后续判断是否胜利使用
    this.surplusMine = 0; //剩余雷数
    this.mineInfo = []; //用于接收随机生成的雷的信息
    this.tdsArr = [] //存放单元格的信息
    this.isPlay = false; //是否开始玩
    this.openClass = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
    this.gameBox = document.getElementById("gameBox");
    this.table = document.createElement("table"); //生成table标签
    this.footerNum = document.getElementById("surplusMine"); //剩余炸弹数量显示框

}

Game.prototype.creatDom = function() { //创建游戏区域,在玩家第一次点击游戏区域的时候执行
    this.table.oncontextmenu = function() { return false }; //清除默认右键单机事件
    for (var i = 0; i < this.gameBox.children.length; i++) { //为防止重新开始游戏时,重复生成多个table,在添加之前先删除之前的
        var childNod = this.gameBox.children[i];
        this.gameBox.removeChild(childNod);
    }

    for (var i = 0; i < this.tr; i++) {
        var tr = document.createElement("tr");
        this.tdsArr[i] = []; //为每一行生成一个数组

        for (var j = 0; j < this.td; j++) {
            var td = document.createElement("td");
            tr.appendChild(td); //将生成的td插入到tr中
            this.tdsArr[i][j] = td;
            td.info = { //info属性包括了单元格的所有信息,很重要
                type: "number", //格子类型,用于判断是否时炸弹
                x: i, //行
                y: j, //列
                value: 0, //当该格子周围有炸弹时显示该数值,生成炸弹的时候会++
                isOpen: false, //判断该单元格是否被打开
                isFlag: false //判断是否有标记flag
            }
        }
        this.table.appendChild(tr); //见tr插入到table中
    }
    this.gameBox.appendChild(this.table);
}

Game.prototype.creatMine = function(event, target) { //生成炸弹,该方法会在用户第一次点击棋盘的时候执行一次

    var This = this;
    for (var i = 0; true; i++) { //随机生成炸弹,生成扎当数与设定扎当书mineNum相同时终止循环
        var randomX = Math.floor(Math.random() * this.tr), //随机生成炸弹的行数
            randomY = Math.floor(Math.random() * this.td); //随机生成炸弹的列数
        //   console.log(randomX + " " + randomY)
        if (target.info.x != randomX || target.info.y != randomY) { //保证第一次点击的时候不是炸弹
            if (this.tdsArr[randomX][randomY].info.type != "mine") { //保证每次生成的雷的位置不重复

                this.tdsArr[randomX][randomY].info.type = "mine"; //单元格更改属性为雷
                this.surplusMine++; //生成雷的数量+1
                this.mineInfo.push(this.tdsArr[randomX][randomY]); //将生成的雷的信息存放到this变量中,方便后续使用

            }
            if (this.surplusMine >= this.mineNum) { //当生成的炸弹数量等于设定的数量后跳出循环
                break;
            }
        }
    }

    //为每个炸弹周围的方格添加数字
    for (var i = 0; i < this.mineInfo.length; i++) {
        var around = this.getAround(this.mineInfo[i], This); //获取每个炸弹的周围方格

        for (var j = 0; j < around.length; j++) { //将周围每个方格的value++
            around[j].info.value += 1;
        }
    }


}

Game.prototype.getAround = function(thisCell, This) { //获取某个方格的周围非炸弹方格,需要传递一个单元格dom元素,Game的this
    var x = thisCell.info.x, //行
        y = thisCell.info.y, //列
        result = [];
    for (var j = x - 1; j <= x + 1; j++) {
        for (var k = y - 1; k <= y + 1; k++) {
            if ( //游戏区域的边界,行数x和列数y不能为负数,且不能超过设定的行数和列数
                j < 0 ||
                k < 0 ||
                j > (This.tr - 1) ||
                k > (This.td - 1) ||
                //同时跳过自身和周边是雷的方格
                This.tdsArr[j][k].info.type == "mine" ||
                (j == x && k == y)

            ) {
                continue; //满足上述条件是则跳过当此循环;
            } else {
                result.push(This.tdsArr[j][k]) //将符合的单元格push到result中返回
            }
        }
    }
    return result;
}

Game.prototype.lifeMouse = function(event, target) { //左键点击事件
    var This = this; //用变量的方式将Game的this传递到函数中
    var noOpen = 0; //没有被打开的格子数量
    if (!target.info.isFlag) { //表示该必须没有被右键标记才能鼠标左击
        if (target.info.type == "number") { //是数字时,则可视化

            function getAllZero(target, This) { //递归函数
                //   console.log(target.info)
                if (target.info.isFlag) { //当这个单元格之前有被标记过flag时,则将剩余炸弹数+1
                    This.surplusMine += 1;
                    target.info.isFlag = false; //单元格被打开后初始化flag
                }
                if (target.info.value == 0) { //等于格子的value等于0的时候

                    target.className = This.openClass[target.info.value]; //可视化

                    target.info.isOpen = true; //表示该单元格被打开

                    var thisAround = This.getAround(target, This); //获取该单元格周围的格子信息

                    for (var i = 0; i < thisAround.length; i++) {
                        //   console.log(thisAround[i].info.isOpen)
                        if (!thisAround[i].info.isOpen) { //递归的条件,当格子的open为true时不执行

                            getAllZero(thisAround[i], This) //执行递归
                        }

                    }

                } else {
                    target.innerHTML = target.info.value;
                    target.className = This.openClass[target.info.value]; //可视化
                    target.info.isOpen = true; //表示单元格被打开
                    target.info.isFlag = false; //单元格被打开后初始化flag

                }
            }

            getAllZero(target, This); //首次执行

            //每次鼠标左键点击的时候都需要检查一下没有被打开的方格数量,每有一个则noOpen++
            for (var i = 0; i < this.tr; i++) {
                for (var j = 0; j < this.tr; j++) {
                    if (this.tdsArr[i][j].info.isOpen == false) {
                        noOpen++;
                    }
                }

            }
            //当noOpen的数量与炸弹数量相同时,说明剩余的方格全是雷,游戏通过
            if (noOpen == this.mineNum) {
                console.log(noOpen)
                this.gameWin();
            }

        } else { //点击到了炸弹,游戏结束
            this.gameOver(target)
        }
    }



}

Game.prototype.rightMouse = function(target) { //鼠标右键点击执行
    if (!target.info.isOpen) {
        if (!target.info.isFlag) { //标记
            target.className = "targetFlag"; //显示旗帜
            target.info.isFlag = true; //表示该方格已经被标记
            this.surplusMine -= 1; //每标记一个方格,剩余炸弹数量-=1
            //   console.log(this.surplusMine)
        } else { //取消标记
            target.className = ""; //去掉旗帜
            target.info.isFlag = false;
            this.surplusMine += 1;
            //   console.log(this.surplusMine)

        }

        var isWin = true;
        if (this.surplusMine == 0) { //标记完所有flag时,遍历所有单元格
            //   console.log(this.mineInfo.length)
            for (var i = 0; i < this.mineInfo.length; i++) {
                console.log(this.mineInfo[i].info.isFlag)
                if (!this.mineInfo[i].info.isFlag) { //检查每个雷的isFlag属性是否被标记,只要有一个为false则输掉游戏
                    isWin = false;
                    this.gameOver(target, 1);
                    break;
                }
            }
            isWin ? this.gameWin(1) : 0; //三目运算符号
        }
    }
}

Game.prototype.gameOver = function(target, code) { //游戏结束,code为触发代码,当旗用完了时为1,点击到炸弹为0
    //   console.log(this.mineInfo)
    var mineInfoLen = this.mineInfo.length;
    for (var i = 0; i < mineInfoLen; i++) { //显示每个雷的位置
        this.mineInfo[i].className = "mine";
    }
    this.table.onmousedown = false; //取消鼠标事件

    if (code+1) {
        alert("旗帜用完了,没有排除所有雷,游戏结束")
    } else {
        target.className = "targetMine"; //触发雷标红色
        alert("你被炸弹炸死了,游戏结束")
    }

}

Game.prototype.gameWin = function(code) { //游戏胜利
    if (code) {
        alert("你成功标记所有地雷,游戏通过")
    } else {
        alert("你找到了所有安全区域,游戏通过")
    }
    this.table.onmousedown = false;


}

Game.prototype.play = function() {
    var This = this; //需要将this传递到事件函数中使用
    this.table.onmousedown = function(event) {
        event = event || window.event; //兼容IE
        target = event.target 

        if (!this.isPlay) { //首次点击初始化棋盘,随机生成炸弹
            this.isPlay = true;
            This.creatMine(event, target);
        }

        if (event.button == 0) { //鼠标左键点击时执行
            This.lifeMouse(event, target);

        } else if (event.button == 2) { //右键点击执行
            This.rightMouse(target)
        }
        This.footerNum.innerHTML = This.surplusMine; //每次点击右键,刷新页面下方的剩余雷数
    }
}

Game.prototype.tablePos = function() { //将table居中显示

    this.table.style.width = this.table.offsetWidth + "px"
    this.table.style.height = this.table.offsetHeight + "px"
}


function addEvent(elem, type, handle) { //添加事件函数
    if (elem.addEventListener) { //w3c标准
        elem.addEventListener(type, handle, false);
    } else if (elem.attachEvent) { //IE9及以下
        elem.attachEvent("on" + type, function() {
            handle.call(elem);
        })
    } else { //其他情况
        elem["on" + type] = handle;
    }
}

Game.prototype.setDegree = function() { //调整难度
    var button = document.getElementsByTagName("button");

    addEvent(button[0], "click", function() { //入门
        var game = new Game(3, 3, 1);
        game.creatDom();
        game.play();
        game.tablePos();
    });

    addEvent(button[1], "click", function() { //简单
        var game = new Game(10, 10, 10);
        game.creatDom();
        game.play();
        game.tablePos();
    });

    addEvent(button[2], "click", function() { //一般
        var game = new Game(16, 16, 50);
        game.creatDom();
        game.play();
        game.tablePos();
    });

    addEvent(button[3], "click", function() { //困难
        var game = new Game(30, 30, 99);
        game.creatDom();
        game.play();
        game.tablePos();
    });

    addEvent(button[4], "click", function() { //终极
        var game = new Game(33, 55, 150);
        game.creatDom();
        game.play();
        game.tablePos();
    });


}

//   默认棋盘
var game = new Game(3,3,1);
game.creatDom();
game.play();
game.tablePos();
game.setDegree()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值