手把手带你做个扫雷游戏

论游戏中,最深入人心的游戏是什么?最经典的游戏是什么?理所当然,是《扫雷》。

项目地址:项目地址

手把手带你做个扫雷游戏_第1张图片
游戏样例

手把手带你做个扫雷游戏_第2张图片
游戏样例

这就是游戏的整体ui。

首先制作游戏的h5骨架:
可以使用一个div作为容器来放置每个方格,至于时间表,可以最为图片:

index.html




    
    扫雷
    
    


然后编写下css文件,设置html部件的样式
css/index.css

#chess{
    border: #000 solid 1px;
    margin: 10px auto;
}
.block{
    width: 28px;
    height: 28px;
    margin: 0;
    border: #000 solid 1px;
    background-color: #eee;
    float: left;
    font-weight: bold;
    text-align: center;
    line-height: 30px;
    font-size: 20px;
    cursor: pointer;
}
.block:hover{
    background-color: #ccc;
}
#info{
    margin: 0 auto;
    text-align: center;
}
.face{
    border: 2px solid #808080;
    border-left-color: #fff;
    border-top-color: #fff;
    height: 20px;
    width: 20px
}
.face:active{
    border-top:2px solid #808080;
    border-bottom:1px solid #808080;
    border-right:1px solid #808080;
    border-left:2px solid #808080;
}

接下来就开始实现游戏的逻辑实现,首先初始化一些基本变量与数组:

var chess = [];// 存储雷区的值
const num = 100;// 存储地雷数
var surplusNum = num;// 存储剩余地雷数
var styles = [
    "#00f",
    "#0f0",
    "#f00",
    "#08f",
    "#f30",
    "#0fa",
    "#943",
    "#eee"
];// 存储不同数字的颜色样式
var die = false;// 存储是否游戏结束
var chessJq = $("#chess");// 为雷区的jQuery对象
var chessLength = 25;// 为雷区的边长

为了能在游戏结束后能重复开始游戏,则我们将一些初始化代码放入init函数中,并在开始调用它:

init();
function init() {
    // 判断是否地雷数大于格子数
    if (num > Math.pow(chessLength,2))
        return;
    // 设置雷区长宽
    $("#chess").css({
        "width": chessLength * 30,
        "height": chessLength * 30
    });
    // 初始化雷区
    for (let i = 0 ; i < chessLength ; i++){
        chess[i] = [];
        for (let j = 0 ; j < chessLength ; j++){
            chess[i][j] = 0;
        }
    }
    for (let i = 0 ; i < num ; i++){
        while (true){
            var x = Math.floor(Math.random() * chess.length),y = Math.floor(Math.random() * chess.length);
            if (chess[y][x] == 0){
                chess[y][x] = -1;
                break;
            }
        }
    }
    // 初始化数字标记
    for (let i = 0 ; i < chess.length ; i++){
        for (let j = 0 ; j < chess.length ; j++){
            if (chess[i][j] == -1)
                continue;
            chess[i][j] += get(i - 1,j);
            chess[i][j] += get(i + 1,j);
            chess[i][j] += get(i,j - 1);
            chess[i][j] += get(i,j + 1);
            chess[i][j] += get(i - 1,j - 1);
            chess[i][j] += get(i + 1,j + 1);
            chess[i][j] += get(i + 1,j - 1);
            chess[i][j] += get(i - 1,j + 1);
        }
    }
    // 清空雷区
    chessJq.empty();
    for (let i = 0 ; i < chess.length ; i++){
        for (let j = 0 ; j < chess.length ; j++){
            // chessJq.append("
"); // if (chess[i][j] > 0){ // $("#" + i + "-" + j).html(chess[i][j]); // } chessJq.append("
"); } } surplusNum = num; update(); } function get(i,j) { if (i < 0 || i >= chess.length || j < 0 || j >= chess.length) return 0; if (chess[i][j] == -1) return 1; return 0; }

然后,接着实现点击雷区方格露出数字、与右击标记的代码,对此,可以添加一个mousedown的事件。

$(".block").mousedown(function (e) {
    if (die)
        return;
    var me = $(this);
    if (e.which == 1){// left click
        open(me,true,0);
    } else {// right click
        if (me.html().search(/0/g) !== -1){
            me.html("");
            surplusNum--;
            update();
        } else if (me.html().search(/flag/g) !== -1) {
            me.html("");
            surplusNum++;
            update();
        } else {
            me.html("");
        }
        if (surplusNum == 0){
            for (let i = 0 ; i < chess.length ; i++){
                for (let j = 0 ; j < chess.length ; j++){
                    if (chess[i][j] == -1 && $("#" + i + "-" + j).html().search("flag") == -1){
                        die = true;
                        break;
                    }
                }
            }
            if (die){
                $("#start").attr("src","img/face_fail.bmp");
                dieShow();
            } else {
                $("#start").attr("src","img/face-win.bmp");
            }
        }
    }
});

细心的同学们肯定发现了,接着,我们要开始实现open函数,该函数应该有两个模式,一个是程序自动翻出附近的数字,一个是打开用户操作的方格。可以使用传一个布尔值来判断,并使用递归实现自动翻出附近的数字。


function open(me,canBoom,level) {
    var id = me.attr("id");
    var tmp = id.split("-");
    var x = tmp[1] * 1;
    var y = tmp[0] * 1;
    if (level > 5){
        return;
    }
    if (me.html().search(/flag/g) != -1 || me.html().search(/ask/g) != -1)
        return;
    if (chess[y][x] == -1 && canBoom){
        me.html("");
        die = true;
        $("#start").attr("src","img/face_fail.bmp");
        dieShow();
    } else if (chess[y][x] > 0){
        me.html(chess[y][x]);
        me.css({
            "color": styles[chess[y][x]],
            "background-image": "url(\"img/0.bmp\")"
        });
        let tmp = $("#" + y + "-" + x);
        if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1)
            return;
        if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 ||
            chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1
        ){
            return;
        }
        open($("#" + (y - 1) + "-" + (x)),false,level + 1);
        open($("#" + (y + 1) + "-" + (x)),false,level + 1);
        open($("#" + (y) + "-" + (x + 1)),false,level + 1);
        open($("#" + (y) + "-" + (x - 1)),false,level + 1);
        open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1);
        open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1);
        open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1);
        open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1);
    } else {
        me.html("");
        let tmp = $("#" + y + "-" + x);
        if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1)
            return;
        if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 ||
            chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1
        ){
            return;
        }
        open($("#" + (y - 1) + "-" + (x)),false,level + 1);
        open($("#" + (y + 1) + "-" + (x)),false,level + 1);
        open($("#" + (y) + "-" + (x + 1)),false,level + 1);
        open($("#" + (y) + "-" + (x - 1)),false,level + 1);
        open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1);
        open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1);
        open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1);
        open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1);
    }
}

仔细阅读以上代码,可以发现还有两个函数未实现: update与dieShow。

先啃软柿子,编写update的代码:

function update() {
    surplusNum += "";
    if (surplusNum.length == 2)
        surplusNum = "0" + surplusNum;
    if (surplusNum.length == 1)
        surplusNum = "00" + surplusNum;
    if (surplusNum.length == 0)
        surplusNum = "000";
    $("#b-h").attr("src","img/d" + surplusNum.charAt(0) + ".bmp");
    $("#b-t").attr("src","img/d" + surplusNum.charAt(1) + ".bmp");
    $("#b-o").attr("src","img/d" + surplusNum.charAt(2) + ".bmp");
    surplusNum *= 1;
}

至于dieShow的代码,可以通过遍历存储雷区的数组编写:

function dieShow() {
    for (let i = 0 ; i < chess.length ; i++){
        for (let j = 0 ; j < chess.length ; j++){
            let tmp = $("#" + i + "-" + j);
            if (chess[i][j] == -1){// have boom
                if (tmp.html().search(/blood/g) != -1)
                    continue;
                tmp.html("");
            } else if (tmp.html().search(/flag/g) != -1 && chess[i][j] != -1){// not have boom and user is marked
                tmp.html("");
            } else if (chess[i][j] > 0){
                me.html(chess[i][j]);
                tmp.css({
                    "color": styles[chess[i][j]],
                    "background-image": "url(\"img/0.bmp\")"
                });
            } else {
                tmp.html("");
            }
        }
    }
}

再编写点击按钮重来的代码

$("#start").click(function () {
    $(this).attr("src","img/face_normal.bmp");
    die = false;
    init();
});

这时测试,游戏就基本完成了...等等,为什么右击无法标记?

因为我们忘写了一个重要而简洁的事件响应函数

$(".block").bind("contextmenu", function(){
    return false;
});

最后js部分全部代码如下:

var chess = [];
const num = 100;
var surplusNum = num;
var styles = [
    "#00f",
    "#0f0",
    "#f00",
    "#08f",
    "#f30",
    "#0fa",
    "#943",
    "#eee"
];
var die = false;
var chessJq = $("#chess");
var chessLength = 25;
init();
function init() {
    if (num > Math.pow(chessLength,2))
        return;
    $("#chess").css({
        "width": chessLength * 30,
        "height": chessLength * 30
    });
    for (let i = 0 ; i < chessLength ; i++){
        chess[i] = [];
        for (let j = 0 ; j < chessLength ; j++){
            chess[i][j] = 0;
        }
    }
    for (let i = 0 ; i < num ; i++){
        while (true){
            var x = Math.floor(Math.random() * chess.length),y = Math.floor(Math.random() * chess.length);
            if (chess[y][x] == 0){
                chess[y][x] = -1;
                break;
            }
        }
    }
    for (let i = 0 ; i < chess.length ; i++){
        for (let j = 0 ; j < chess.length ; j++){
            if (chess[i][j] == -1)
                continue;
            chess[i][j] += get(i - 1,j);
            chess[i][j] += get(i + 1,j);
            chess[i][j] += get(i,j - 1);
            chess[i][j] += get(i,j + 1);
            chess[i][j] += get(i - 1,j - 1);
            chess[i][j] += get(i + 1,j + 1);
            chess[i][j] += get(i + 1,j - 1);
            chess[i][j] += get(i - 1,j + 1);
        }
    }
    chessJq.empty();
    for (let i = 0 ; i < chess.length ; i++){
        for (let j = 0 ; j < chess.length ; j++){
            // chessJq.append("
"); // if (chess[i][j] > 0){ // $("#" + i + "-" + j).html(chess[i][j]); // } chessJq.append("
"); } } $(".block").mousedown(function (e) { if (die) return; var me = $(this); if (e.which == 1){// left click open(me,true,0); } else {// right click if (me.html().search(/0/g) !== -1){ me.html(""); surplusNum--; update(); } else if (me.html().search(/flag/g) !== -1) { me.html(""); surplusNum++; update(); } else { me.html(""); } if (surplusNum == 0){ for (let i = 0 ; i < chess.length ; i++){ for (let j = 0 ; j < chess.length ; j++){ if (chess[i][j] == -1 && $("#" + i + "-" + j).html().search("flag") == -1){ die = true; break; } } } if (die){ $("#start").attr("src","img/face_fail.bmp"); dieShow(); } else { $("#start").attr("src","img/face-win.bmp"); } } } }); $(".block").bind("contextmenu", function(){ return false; }); surplusNum = num; update(); } function dieShow() { for (let i = 0 ; i < chess.length ; i++){ for (let j = 0 ; j < chess.length ; j++){ let tmp = $("#" + i + "-" + j); if (chess[i][j] == -1){// have boom if (tmp.html().search(/blood/g) != -1) continue; tmp.html(""); } else if (tmp.html().search(/flag/g) != -1 && chess[i][j] != -1){// not have boom and user is marked tmp.html(""); } else if (chess[i][j] > 0){ me.html(chess[i][j]); tmp.css({ "color": styles[chess[i][j]], "background-image": "url(\"img/0.bmp\")" }); } else { tmp.html(""); } } } } function open(me,canBoom,level) { var id = me.attr("id"); var tmp = id.split("-"); var x = tmp[1] * 1; var y = tmp[0] * 1; if (level > 5){ return; } if (me.html().search(/flag/g) != -1 || me.html().search(/ask/g) != -1) return; if (chess[y][x] == -1 && canBoom){ me.html(""); die = true; $("#start").attr("src","img/face_fail.bmp"); dieShow(); } else if (chess[y][x] > 0){ me.html(chess[y][x]); me.css({ "color": styles[chess[y][x]], "background-image": "url(\"img/0.bmp\")" }); let tmp = $("#" + y + "-" + x); if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1) return; if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 || chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1 ){ return; } open($("#" + (y - 1) + "-" + (x)),false,level + 1); open($("#" + (y + 1) + "-" + (x)),false,level + 1); open($("#" + (y) + "-" + (x + 1)),false,level + 1); open($("#" + (y) + "-" + (x - 1)),false,level + 1); open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1); open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1); open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1); open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1); } else { me.html(""); let tmp = $("#" + y + "-" + x); if (tmp.html().search(/flag/g) != -1 || tmp.html().search(/ask/g) != -1) return; if (chess[y - 1][x] == -1 || chess[y + 1][x] == -1 || chess[y][x + 1] == -1 || chess[y][x - 1] == -1 || chess[y - 1][x + 1] == -1 || chess[y + 1][x - 1] == -1 || chess[y + 1][x + 1] == -1 || chess[y - 1][x - 1] == -1 ){ return; } open($("#" + (y - 1) + "-" + (x)),false,level + 1); open($("#" + (y + 1) + "-" + (x)),false,level + 1); open($("#" + (y) + "-" + (x + 1)),false,level + 1); open($("#" + (y) + "-" + (x - 1)),false,level + 1); open($("#" + (y - 1) + "-" + (x + 1)),false,level + 1); open($("#" + (y + 1) + "-" + (x - 1)),false,level + 1); open($("#" + (y + 1) + "-" + (x + 1)),false,level + 1); open($("#" + (y - 1) + "-" + (x - 1)),false,level + 1); } } function get(i,j) { if (i < 0 || i >= chess.length || j < 0 || j >= chess.length) return 0; if (chess[i][j] == -1) return 1; return 0; } function update() { surplusNum += ""; if (surplusNum.length == 2) surplusNum = "0" + surplusNum; if (surplusNum.length == 1) surplusNum = "00" + surplusNum; if (surplusNum.length == 0) surplusNum = "000"; $("#b-h").attr("src","img/d" + surplusNum.charAt(0) + ".bmp"); $("#b-t").attr("src","img/d" + surplusNum.charAt(1) + ".bmp"); $("#b-o").attr("src","img/d" + surplusNum.charAt(2) + ".bmp"); surplusNum *= 1; } $("#start").click(function () { $(this).attr("src","img/face_normal.bmp"); die = false; init(); });
手把手带你做个扫雷游戏_第3张图片
引导图-恢复的.png

你可能感兴趣的:(手把手带你做个扫雷游戏)