• 手把手教你使用JavaScript打造一款扫雷游戏


    大家好,我是皮皮。

    扫雷大家都玩过,今天我们就是用JavaScript来打造扫雷游戏。废话不多说,直接看下效果;

    image

    上图是失败后的结果。

    一、思路分析

    我们新建一个首页,在首页放置一个点击开始游戏的按钮,动态生成100个小格,即100div;然后通过点击div进行扫雷操作,然后扫雷成功或者失败显示对应的结果;

    二、静态页面搭建

    2.1 结构层

    <body>
        <div class="wrapper">
            <div class="btn" id="btn"></div>  <!-- 开始游戏按钮-->
            <div class="box" id="box"></div>  <!-- 存放小雷的div-->
            <div class="flagBox" id="flagBox"> <!-- 游戏结束才显示的当前雷数的div-->
                当前剩余雷数:
                <span id="score">10</span>
            </div>
            <div class="alertBox" id="alertBox">  <!-- Game over弹出的框(窗口)-->
                <div class="alertImg" id="alertImg">
                    <div class="close" id="close"></div>
                </div>
            </div>
        </div>
    </body>
    
    

    2.2 样式层

    清楚默认边距

    *{
        margin:0;
        padding:0;
    }
    
    

    页面最大div

    .wrapper {
        100%;
        height:1000px;
        position: fixed;
        top:0;
        left:0;
        background-image: url('img/bg.jpg');
        background-size: 100% 100%;
    }
    
    

    效果如下:

    image

    开始游戏按钮

    .btn{
        height:140px;
        170px;
        position:absolute;
        left:50px;
        background-image: url('img/startGame.png');
        background-size: 100% 100%;
        cursor: pointer;
    }
    
    

    储存雷的大div

    .box{
        height:500px;
        500px;
        transform: perspective(800px) rotateX(45deg);
        margin:20px auto;
        border-top:1px solid #B25F27;
        border-left:1px solid #B25F27;
        box-shadow:  5px 5px 5px rgba(0,0,0,0.3);
        display:none; /* 先设置为none,开始游戏后显示block */ 
    }
    
    

    每一个方块的小div(一共100个)

    .block{
        49px;
        height:49px;
        border-right:1px solid #B25F27;
        border-bottom:1px solid #B25F27;
        box-shadow: 0 0 4px #333 inset;
        background-image: url('img/cao.jpg');
        float: left;
    }
    
    

    当前所剩雷数

    .flagBox{
        position:absolute;
        top:50px;
        left:50%;
        200px;
        height:50px;
        margin-left:-100px;
        color:#333;
        font-size:20px;
        font-weight: bolder;
        display:none; /* 先设置为none,开始游戏后显示block */ 
    }
    
    

    Game Over

    .alertBox{
        display:none; /* 先设置为none,开始结束显示block */ 
        position:absolute;
        100%;
        height:100%;
        left:0;
        top:0;
        background-color: rgba(0,0,0,0.2);
    }
    
    

    游戏结束弹出窗口右上角的X

    .close{
        position:absolute;
        right:0;
        top:0;
        height:40px;
        40px;
        background-image: url('img/closeBtn.png');
        background-size: 100% 100%;
        cursor: pointer;
    
    }
    
    

    三、js页面交互

    3.1 获取元素及变量初始化

    var startBtn = document.getElementById('btn');
    var box = document.getElementById('box');
    var flagBox = document.getElementById('flagBox');
    var alertBox = document.getElementById('alertBox');
    var alertImg = document.getElementById('alertImg');
    var closeBtn = document.getElementById('close');
    var score = document.getElementById('score');
    // 先声明变量,但是不初始化
    var minesNum;
    var mineOver;
    var block;
    var mineMap = [];
    var startGameBool = true;
    
    

    3.2 10个雷的初始化设置

    function init() {
        minesNum = 10;
        mineOver = 10;
        score.innerHTML = mineOver;
    
        for (var i = 0; i < 10; i++) { // 双层循环 10 * 10 个div
            for (var j = 0; j < 10; j++) {
                var con = document.createElement('div');
                con.classList.add('block'); // 给创建出来的div添加类名 block 
                con.setAttribute('id', i + '-' + j);
                box.appendChild(con);
                mineMap.push({ mine: 0 });
            }
        }
        block = document.getElementsByClassName('block');
        while (minesNum) { // 创建一个10次的循环,即设置10个雷
            var mineIndex = Math.floor(Math.random() * 100);
            if (mineMap[mineIndex].mine === 0) {
                mineMap[mineIndex].mine = 1;
                block[mineIndex].classList.add('isLei'); // 10个雷有小div的block类属性,还有自己的属性,isLei
                minesNum--;
            }
        }
    }
    
    

    3.3 游戏开始事件封装

    function bindEvent() {
        startBtn.onclick = function () { // 开始按钮点击事件
            if(startGameBool){
                box.style.display = 'block';
                flagBox.style.display = 'block';
                init();
                startGameBool = false;
            }
        }
        box.oncontextmenu = function () {
            return false;
        }
        box.onmousedown = function (e) { // 小div鼠标按下事件封装
            var event = e.target;
            if (e.which == 1) { //Netscape/Firefox/Opera中不支持 window.event.keyCode,需要用event.which代替
                leftClick(event);
            } else if (e.which == 3) {
                rightClick(event);
            }
        }
        closeBtn.onclick = function () { // 游戏结束,弹出game over窗口的关闭按钮事件封装
            alertBox.style.display = 'none';
            flagBox.style.display = 'none';
            box.style.display = 'none';
            box.innerHTML = '';
            startGameBool = true;
        }
    }
    
    

    3.4 核心事件函数封装

    leftClick 没有雷 --> 显示数字(代表以当前小格为中心周围8个格的雷数)扩散(当前周围八个格没有雷) 有雷 --> game Over

    function leftClick(dom) {
        if(dom.classList.contains('flag')){
            return;
        }
        var isLei = document.getElementsByClassName('isLei'); // 获得前面的10个雷的div
        if (dom && dom.classList.contains('isLei')) { // 判断是不是雷块
            for (var i = 0; i < isLei.length; i++) {
                isLei[i].classList.add('show'); // 显示地雷背景图
            }
            setTimeout(function () {
                alertBox.style.display = 'block';
                alertImg.style.backgroundImage = 'url("img/over.jpg")';  // 上面显示雷,标志游戏结束
            }, 800)
        } else { // 否则继续扫雷
            var n = 0;
            var posArr = dom && dom.getAttribute('id').split('-');
            var posX = posArr && +posArr[0];
            var posY = posArr && +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 aroundBox = document.getElementById(i + '-' + j);
                    if (aroundBox && aroundBox.classList.contains('isLei')) {
                        n++;
                    }
                }
            }
            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) {
                            if (!nearBox.classList.contains('check')) {
                                nearBox.classList.add('check');
                                leftClick(nearBox);
                            }
                        }
                    }
                }
            }
        }
    }
    
    

    rightClick 没有标记并且没有数字 --> 进行标记;

    有标记 --> 取消标记 --> 标记是否正确,10个都正确标记,提示成功;

    如果已经出现,则点击无效果;

    function rightClick(dom){
        if(dom.classList.contains('num')){ // 如果已经出现,则点击无效果
            return;
        }
        dom.classList.toggle('flag'); // 在元素中切换类名,切换为flag类名,显示红旗背景图;此处的雷被扫除了
        if(dom.classList.contains('isLei') && dom.classList.contains('flag')){
            mineOver --; // 雷数减一
        }
        if(dom.classList.contains('isLei') && !dom.classList.contains('flag')){
            mineOver ++;
        }
    
        score.innerHTML = mineOver;
        if(mineOver == 0){ // 扫完雷,标志雷数量为0
            alertBox.style.display = 'block';
            alertImg.style.backgroundImage = 'url("img/success.png")'; // 游戏胜利
        }
    }
    
    

    3.5 游戏开始

    bindEvent()
    
    

    四、总结

    本文我们通过JavaScript打造了简单的扫雷游戏,首先是设计下简单的界面样式,然后通过扫雷的逻辑动态构建雷块的位置,通过点击小方块进行扫雷,感兴趣的小伙伴可以去试一下。

    小伙伴们,快快用实践一下吧!如果在学习过程中,有遇到任何问题,欢迎加我好友,我拉你进Python学习交流群共同探讨学习。

  • 相关阅读:
    axios——post请求时把对象obj数据转为formdata格式
    【工作问题记录】
    如何在Vue项目中使用Element组件
    Manjaro 安装教程
    真 ● 禁秘技 ● 奥义 ● 终端美化
    Docker下MySQL的安装
    Linux Nvidia显卡驱动安装
    Linux下Matlab的安装
    解决SQLPLUS无法使用上下箭头
    @Transactional+@Autowired出现的lateinit property xx has not been initialized错误
  • 原文地址:https://www.cnblogs.com/dcpeng/p/16039606.html
Copyright © 2020-2023  润新知