当前位置: 移动技术网 > IT编程>开发语言>JavaScript > 那些年我们玩过的2048

那些年我们玩过的2048

2020年07月14日  | 移动技术网IT编程  | 我要评论

那些年我们玩过的2048

首先这个小游戏,相信大家一定都玩过,那今天就一步一步来实现。目前为止,基本功能已经实现,只是没有添加相应的动画效果,待以后有机会补上。

游戏截图

基本思路
当初次游戏的时候,视图更新,分数更新,随机在两个位置生成一个数,当按左键的时候,所有的数字往左移动,如果有相邻相同的数字就相加,同时再随机生成一个,右上下亦是如此。

主要功能
1.游戏初始化:新建游戏4×4的16宫格画布,随机格子上生成2或者4两个数字

2.格子的移动:先判断能否移动,移动后判断能否合并,合并后改变格子颜色和数字

3.新格子的生成:移动一次,就在剩余的空格子中随机生成一个2或者4

4.GAMEOVER:16宫格中没有剩余空格子且不能再向任何方向移动则为游戏失败

分步代码

一、HTML结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2048</title>
    <link rel="shortcout icon" href="https://2048game.com/favicon.ico">
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <p class="score" >SCORE:<span id="score01">0</span></p>
    <div class="play">
        <!-- 第一行 -->
        <div class="cell n2" id="c00">2</div>
        <div class="cell n4" id="c01">4</div>
        <div class="cell n8" id="c02">8</div>
        <div class="cell" id="c03"></div>
        <!-- 第二行 -->
        <div class="cell" id="c10"></div>
        <div class="cell" id="c11"></div>
        <div class="cell" id="c12"></div>
        <div class="cell" id="c13"></div>
        <!-- 第三行 -->
        <div class="cell" id="c20"></div>
        <div class="cell" id="c21"></div>
        <div class="cell" id="c22"></div>
        <div class="cell" id="c23"></div>
        <!-- 第四行 -->
        <div class="cell" id="c30"></div>
        <div class="cell" id="c31"></div>
        <div class="cell" id="c32"></div>
        <div class="cell" id="c33"></div>
    </div>
    <!-- 游戏结束 -->
    <div class="gameover" id="gameover">
        <p>
            GAME OVER!<br>
            SCORE: <span id="score02">0</span><br>
            <a href="">Try again</a>
        </p>
    </div>
    <script src="index.js"></script>
</body>
</html>

HTML结构的主要思路为:利用网格布局将游戏画布的16宫格绘制出来,通过class定制样式,id定位到具体的格子以重绘格子样式
二、CSS样式

*{
    margin: 0;
    padding: 0;
    font-family: "Arial";
}
.score{
    width: 500px;
    margin: auto;
    font-size: 40px;
    padding-top: 50px;
    font-weight: bold;
}
.play{
    width: 500px;
    height: 500px;
    background-color: #BBADA0;
    border-radius: 15px;
    margin: 10px auto;
}
.cell{
    width: 100px;
    height: 100px;
    margin: 20px 0 0 20px;
    background-color: #CDC1B4;
    float: left;
    border-radius: 5px;
    text-align: center;
    line-height: 100px;
    font-size: 40px;
    color: white;
}
.n2{background-color: #eee3da;color: #776e65;}
.n4{background-color: #ede0c8;color: #776e65;}
.n8{background-color: #f2b179;}
.n16{background-color: #f59563;}
.n32{background-color: #f67c5f;}
.n64{background-color: #f65e3b;}
.n128{background-color: #edcf72;}
.n256{background-color: #edcc61;}
.n512{background-color: #9c0;}
.n1024{background-color: #33b5e5;font-size: 40px;}
.n2048{background-color: #09c;font-size: 40px;}
.n4096{background-color: #a6c;font-size: 40px;}
.n8192{background-color: #93c;font-size: 40px;}

.gameover{
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    background-color: rgba(0,0,0,.3);

}
.gameover p{
    width: 400px;
    height: 300px;
    background-color: white;
    border: 1px solid #000;
    border-radius: 10px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -180px;
    margin-top: -140px;

    text-align: center;
    font-weight: bold;
    font-size: 35px;
    line-height: 100px;
}
.gameover a{
    color: white;
    background-color:#f2b179 ;
    text-decoration: none;
    border-radius: 5px;
    padding: 15px;
}

三、JS逻辑代码

方法肯定是多种多样的,这里我们创建了一个game对象,将所有的方法放到这个对象中,直接调用。

完整的移动逻辑应该是:先判断该方向上能否移动,但由于我们的移动是分次传入,只要有一次的结果是可移动,那么整个二维数组都是可移动的,所以要先将分次传入的数组进行移动处理后的结果保存在新数组里,当四次分次传入均处理完且其中有一个能移动时,将新数组的值赋值给原数组board,完成二维数组的条件更新。

var game = {
    data: [], //存放数据
    score: 0, //分数
    status: 0, //当前游戏状态
    gameover: 0,
    gameRunning: 1,
    //开始游戏的方法
    start: function () {
        this.score = 0; //清空分数
        this.data = [
            [0, 0, 0, 0],
            [0, 0, 0, 0],
            [0, 0, 0, 0],
            [0, 0, 0, 0]
        ]
        this.status = this.gameRunning;
        this.randomNum();
        this.randomNum();
        this.dataView();
    },
    //随机数的方法
    randomNum: function () {
        for (;;) {
            var r = Math.floor(Math.random() * 4);
            var c = Math.floor(Math.random() * 4);
            if (this.data[r][c] == 0) {
                var num = Math.random() > 0.2 ? 2 : 4;
                this.data[r][c] = num;
                break;
            }
        }
    },
    //更新视图的方法
    dataView: function () {
        for (var r = 0; r < 4; r++) {
            for (var c = 0; c < 4; c++) {
                var div = document.getElementById("c" + r + c)
                if (this.data[r][c] != 0) {
                    div.innerHTML = this.data[r][c];
                    div.className = "cell n" + this.data[r][c];
                } else {
                    div.innerHTML = " ";
                    div.className = "cell";
                }
            }
        }
        document.getElementById('score01').innerHTML = this.score; //设置游戏分数
        //监测游戏状态
        if (this.status == this.gameover) {
            document.getElementById('score02').innerHTML = this.score;
            document.getElementById('gameover').style.display = 'block';
        } else {
            document.getElementById('gameover').style.display = 'none';
        }

    },
    //判断游戏结束的方法
    isgameover: function () {
        for (var r = 0; r < 4; r++) {
            for (var c = 0; c < 4; c++) {
                //没有结束三种情况
                if (this.data[r][c] == 0) {
                    return false;
                }
                if (c < 3) {
                    if (this.data[r][c] == this.data[r][c + 1]) {
                        return false;
                    }
                }
                if (r < 3) {
                    if (this.data[r][c] == this.data[r + 1][c]) {
                        return false;
                    }
                }
            }
        }
        return true; //表示游戏已经结束
    },
    //左移动
    moveLeft : function () {
        var before = String(this.data); //移动之前
        //处理移动的逻辑
        for (var r = 0; r < 4; r++) {
            this.moveLeftInRow(r);
        }
        var after = String(this.data); //移动之后
        if (before != after) {
            this.randomNum();
            if (this.isgameover()) {
                this.status = this.gameover;
            }
            this.dataView();
        }
    },
    //单独处理每一行
    moveLeftInRow: function (r) {
        for (var c = 0; c < 3; c++) {
            var nextc = this.getLeftNextInRow(r, c);
            if (nextc != -1) {
                if (this.data[r][c] == 0) {
                    this.data[r][c] = this.data[r][nextc];
                    this.data[r][nextc] = 0;
                    c--;
                } else if (this.data[r][c] == this.data[r][nextc]) {
                    this.data[r][c] *= 2;
                    this.score += this.data[r][c];
                    this.data[r][nextc] = 0;
                }
            } else {
                break;
            }
        }
    },
    //查找返回下一个不是0的下标 
    getLeftNextInRow : function (r,c) {
        for (var i = c + 1; i < 4; i++) {
            if (this.data[r][i] != 0) {
                return i;
            }
        }
        return -1;
    },
    //右移动
    moveRight:function(){
        var before = String(this.data); //移动之前
        //处理移动的逻辑
        for (var r = 0; r < 4; r++) {
            this.moveRightInRow(r);
        }
        var after = String(this.data); //移动之后
        if (before != after) {
            this.randomNum();
            if (this.isgameover()) {
                this.status = this.gameover;
            }
            this.dataView();
        }
    },
    //单独处理每一行
    moveRightInRow : function(r){
        for(var c=3;c>0;c--){
            var nextc = this.getRightNextInRow(r, c);
            if (nextc != -1) {
                if (this.data[r][c] == 0) {
                    this.data[r][c] = this.data[r][nextc];
                    this.data[r][nextc] = 0;
                    c++;
                } else if (this.data[r][c] == this.data[r][nextc]) {
                    this.data[r][c] *= 2;
                    this.score += this.data[r][c];
                    this.data[r][nextc] = 0;
                }
            } else {
                break;
            }
        }
    },
    //查找返回下一个不是0的下标 
    getRightNextInRow : function (r,c) {
        for (var i = c - 1; i>=0; i--) {
            if (this.data[r][i] != 0) {
                return i;
            }
        }
        return -1;
    },
    //上移动
    moveUp : function(){
        var before = String(this.data); //移动之前
        //处理移动的逻辑
        for (var c = 0; c < 4; c++) {
            this.moveUpInRow(c);
        }
        var after = String(this.data); //移动之后
        if (before != after) {
            this.randomNum();
            if (this.isgameover()) {
                this.status = this.gameover;
            }
            this.dataView();
        }
    },
     //单独处理每一行
     moveUpInRow : function(c){
        for (var r = 0; r < 3; r++) {
            var nextr = this.getUpNextInRow(r, c);
            if (nextr != -1) {
                if (this.data[r][c] == 0) {
                    this.data[r][c] = this.data[nextr][c];
                    this.data[nextr][c] = 0;
                    r--;
                } else if (this.data[r][c] == this.data[nextr][c]) {
                    this.data[r][c] *= 2;
                    this.score += this.data[r][c];
                    this.data[nextr][c] = 0;
                }
            } else {
                break;
            }
        } 
     },
    //查找返回下一个不是0的下标
     getUpNextInRow : function(r,c){
        for (var i = r + 1; i < 4; i++) {

            if (this.data[i][c] != 0) {
                return i;
            }
        }
        return -1;
     },
    //下移动
    moveDown : function(){
        var before = String(this.data); //移动之前
        //处理移动的逻辑
        for (var c = 0; c < 4; c++) {
            this.moveDownInRow(c);
        }
        var after = String(this.data); //移动之后
        if (before != after) {
            this.randomNum();
            if (this.isgameover()) {
                this.status = this.gameover;
            }
            this.dataView();
        }
    },
    //单独处理每一行
    moveDownInRow : function(c){
        for (var r = 3; r > 0; r--) {
            var nextr = this.getDownNextInRow(r, c);
            if (nextr != -1) {
                if (this.data[r][c] == 0) {
                    this.data[r][c] = this.data[nextr][c];
                    this.data[nextr][c] = 0;
                    r++;
                } else if (this.data[r][c] == this.data[nextr][c]) {
                    this.data[r][c] *= 2;
                    this.score += this.data[r][c];
                    this.data[nextr][c] = 0;
                }
            } else {
                break;
            }
        } 
     },
     //查找返回下一个不是0的下标
     getDownNextInRow : function(r,c){
        for (var i = r - 1; i>=0; i--) {
            if (this.data[i][c] != 0) {
                return i;
            }
        }
        return -1;
     },
}
game.start();
document.onkeydown = function (e) {
    if (e.keyCode == 37) {
        game.moveLeft();
    }
    if(e.keyCode==39){
        game.moveRight();
    }
    if(e.keyCode==38){
        game.moveUp();
    }
    if(e.keyCode==40){
        game.moveDown();
    }
}

本文地址:https://blog.csdn.net/qq_46366496/article/details/107281088

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网