这段时间看了视频,用JavaScript实现2048小游戏,都是一些基本语法和简单逻辑

下面分享一下整个2048游戏代码

2048.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="2048.css">
</head>
<body>
<p>SCORE:<span id="score">0</span></p>
<div id="gridPanel">
    <div id="c00" class="cell"></div>
    <div id="c01" class="cell"></div>
    <div id="c02" class="cell"></div>
    <div id="c03" class="cell"></div>

    <div id="c10" class="cell"></div>
    <div id="c11" class="cell"></div>
    <div id="c12" class="cell"></div>
    <div id="c13" class="cell"></div>

    <div id="c20" class="cell"></div>
    <div id="c21" class="cell"></div>
    <div id="c22" class="cell"></div>
    <div id="c23" class="cell"></div>

    <div id="c30" class="cell"></div>
    <div id="c31" class="cell"></div>
    <div id="c32" class="cell"></div>
    <div id="c33" class="cell"></div>
</div>
<div id="gameOver">
    <p>
        GAME OVER!<br>
        SCORE:<span id="final">0</span><br>
        <a class="btn" href="javascript:game.start();">TRY AGAIN!</a>
    </p>
</div>
    <script src="2048.js"></script>
</body>
</html>

2048.css
#gridPanel{
    width: 480px;
    height: 480px;
    margin: 0 auto;
    position: relative;
    background: #bbada0;
    border-radius: 10px;
}
.cell{
    width: 100px;
    height: 100px;
    border-radius: 6px;
    background:#ccc0b3;
    position: absolute;
    font-size: 60px;
    text-align: center;
    color: #fff;
    line-height: 100px;
}
[id^="c0"]{top:16px}
[id^="c1"]{top:132px}
[id^="c2"]{top:248px}
[id^="c3"]{top:364px}
[id$="0"]{left:16px}
[id$="1"]{left:132px}
[id$="2"]{left:248px}
[id$="3"]{left:364px}

.n2{background-color:#eee3da}
.n4{background-color:#ede0c8}
.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}
.n2048{background-color:#09c}
.n4096{background-color:#a6c}
.n8192{background-color:#93c}
.n2,.n4{color:#776e65}
.n1024,.n2048,.n4096,.n8192{font-size:40px}

p{
    width: 480px;margin: 0 auto;
    font-size: 40px; font-family: Arial;
    font-weight: bold;
    padding-top: 15px;
}
#gameOver{
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(55,55,55,.5);
}
#gameOver>p{
    width: 300px;
    height: 200px;
    background: #FFFFFF;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top:-100px;
    margin-left: -150px;
    text-align: center;
    line-height: 1.5em;
    border-radius: 10px;
    border:1px solid #edcf72;
}
#gameOver .btn{
    padding: 10px;
    color: #FFFFFF;
    background: #9f8d77;
    border-radius: 6px;
    text-decoration: none;
}

2048.js
var game = {
    data: null, RN: 4, CN: 4,//保存游戏二维数组,总行数,总列数
    score: 0,//保存得分
    state: 1,//保存游戏状态:1表示运行,0表示结束
    RUNNING: 1,//专门表示运行状态
    GAMEOVER: 0,//专门表示游戏结束状态
    //每个属性和方法之间必须用逗号隔开!
    //对象自己的方法要使用自己的属性,必须this.
    start() {//启动游戏
        this.state = this.RUNNING;//重置游戏状态为运行中
        this.score = 0;//分数清0
        this.data = [];//新建空数组保存在data中
        //r从0开始,到<RN结束
        for (var r = 0; r < this.RN; r++) {
            //新建空数组保存到data中r行
            this.data[r] = [];
            //c从0开始,到<CN结束
            for (var c = 0; c < this.CN; c++) {
                //设置data中r行c列的值为0
                this.data[r][c] = 0;
            }
        }//(遍历结束)
        this.randomNum();
        this.randomNum();
        this.updateView();
        //事件:内容/设备状态的改变
        //事件处理函数:在事件发生时自动执行的操作
        document.onkeydown = function (e) {
            //this->.前的document->game
            if (this.state == this.RUNNING)
                switch (e.keyCode) {
                    case 37://左移
                        this.moveLeft();
                        break;
                    case 38: //上移
                        this.moveUp();
                        break;
                    case 39: //右移
                        this.moveRight();
                        break;
                    case 40: //下移
                        this.moveDown();
                        break;
                }
        }.bind(this);
    },
    move(callback) {//所有移动中相同的代码
        //为data拍照,保存在before中
        var before = String(this.data);
        callback.call(this);
        //为data拍照,保存在after中
        var after = String(this.data);
        if (before != after) {//如果发生了移动
            this.randomNum();//随机生成数
            if (this.isGameOver())//如果游戏结束
            {
                this.state = this.GAMEOVER;
            }//修改游戏状态
            this.updateView();//更新页面
        }
    },
    moveLeft() {
        this.move(function () {
            //r从0开始,到<RN结束
            for (var r = 0; r < this.RN; r++) {
                this.moveLeftInRow(r);//左移第r行
            }
        });
    },
    isGameOver() {//判断游戏是否结束
        //遍历data
        for (var r = 0; r < this.RN; r++) {
            for (var c = 0; c < this.CN; c++) {
                //如果当前元素是0,返回false
                if (this.data[r][c] == 0) return false;
                //否则,如果c<CN-1且当前元素等于右侧元素
                else if (c < this.CN - 1 && (this.data[r][c] == this.data[r][c + 1])) {
                    return false;//返回false
                }
                //否则,如果r<RN-1且当前元素等于下方元素
                else if (r < this.RN - 1 && (this.data[r][c] == this.data[r + 1][c])) {
                    return false;//返回false
                }
            }
        }//(遍历结束)
        return true;//返回true
    },
    moveLeftInRow(r) {//左移第r行
        //c从0开始,到<CN-1结束,遍历r行中每个格
        for (var c = 0; c < this.CN - 1; c++) {
            //找r行c列右侧下一个不为0的位置nextc
            var nextc = this.getNextInRow(r, c);
            //如果没找到,就退出循环
            if (nextc == -1) break;
            else {//否则
                //如果c列的值是0
                if (this.data[r][c] == 0) {
                    //将nextc列的值赋值给c列
                    this.data[r][c] = this.data[r][nextc];
                    //将nextc列的值置为0
                    this.data[r][nextc] = 0;
                    c--;//c留在原地
                } else if (this.data[r][c] == this.data[r][nextc]) {
                    //否则 如果c列的值等于nextc列的值
                    //将c列的值*2
                    this.data[r][c] *= 2;
                    this.score += this.data[r][c];
                    //将nextc列置为0
                    this.data[r][nextc] = 0;
                }
            }
        }
    },
    getNextInRow(r, c) {//找r行c列右侧下一个不为0的位置
        //i从c+1开始,到<CN结束
        for (var i = c + 1; i < this.CN; i++) {
            //如果i位置不是0,返回i
            if (this.data[r][i] != 0) return i;
        }//(遍历结束)
        return -1;  //返回-1
    },
    moveRight() {
        this.move(function () {
            //遍历data中每一行
            for (var r = 0; r < this.RN; r++) {
                this.moveRightInRow(r)//右移第r行
            }
        });
    },
    moveRightInRow(r) {//右移第r行
        //c从CN-1开始,到>0结束,反向遍历r行中每个格
        for (var c = this.CN - 1; c > 0; c--) {
            //找r行c列左侧前一个不为0的位置prevc
            var prevc = this.getPrevInRow(r, c);
            //如果prevc为-1,就退出循环
            if (prevc == -1) {
                break;
            }
            else {//否则
                //如果c列的值是0
                if (this.data[r][c] == 0) {
                    //将prevc列的值赋值给c列
                    this.data[r][c] = this.data[r][prevc];
                    //将prevc列的值置为0
                    this.data[r][prevc] = 0;
                    c++;//c留在原地
                } else if (this.data[r][c] == this.data[r][prevc]) {
                    //否则 如果c列的值等于prevc列的值
                    //将c列的值*2
                    this.data[r][c] *= 2;
                    this.score += this.data[r][c];
                    //将prevc列置为0
                    this.data[r][prevc] = 0;
                }
            }
        }
    },
    getPrevInRow(r, c) {//查找r行c列左侧前一个不为0的位置
        //i从c-1开始,到>=0结束,每次-1
        for (var i = c - 1; i >= 0; i--) {
            //如果data中r行i列的值不为0,就返回i
            if (this.data[r][i] != 0) return i;
        }//循环结束
        //返回-1
        return -1;
    },
    moveUp() {
        this.move(function () {
            //遍历data中每一列
            for (var c = 0; c < this.CN; c++) {
                //调用moveUpInCol上移第c列
                this.moveUpInCol(c);
            }
        });
    },
    moveUpInCol(c) {
        //r从0开始,到r<RN-1结束,r每次递增1
        for (var r = 0; r < this.RN - 1; r++) {
            //查找r行c列下方下一个不为0的位置nextr
            var nextr = this.getNextInCol(r, c);
            //如果没找到,就退出循环
            if (nextr == -1) break;
            else//否则
            //如果r位置c列的值为0
            if (this.data[r][c] == 0) {
                //将nextr位置c列的值赋值给r位置
                this.data[r][c] = this.data[nextr][c];
                //将nextr位置c列置为0
                this.data[nextr][c] = 0;
                r--;//r留在原地
            } else if (this.data[r][c] == this.data[nextr][c]) {//否则,如果r位置c列的值等于nextr位置的值
                //将r位置c列的值*2
                this.data[r][c] *= 2;
                this.score += this.data[r][c];
                //将nextr位置c列的值置为0
                this.data[nextr][c] = 0;
            }
        }
    },
    getNextInCol(r, c) {
        //循环,到<RN结束,r每次递增1
        for (var i = r + 1; i < this.RN; i++) {
            //如果r位置c列不等于0, 就返回r
            if (this.data[i][c] != 0) return i;
        } //(遍历结束)
        return -1;//返回-1
    },
    moveDown() {
        this.move(function () {
            //遍历data中每一列
            for (var c = 0; c < this.CN; c++) {
                //调用moveDownInCol下移第c列
                this.moveDownInCol(c);
            }
        });
    },
    moveDownInCol(c) {
        //r从RN-1开始,到r>0结束,r每次递减1
        for (var r = this.RN - 1; r > 0; r--) {
            //查找r位置c列上方前一个不为0的位置prevr
            var prevr = this.getPrevInCol(r, c);
            //如果没找到,就退出循环
            if (prevr == -1) break;
            else {//否则
                //如果r位置c列的值为0
                if (this.data[r][c] == 0) {
                    //将prevr位置c列的值赋值给r位置
                    this.data[r][c] = this.data[prevr][c];
                    //将prevr位置c列置为0
                    this.data[prevr][c] = 0;
                    r++;//r留在原地
                } else if (this.data[r][c] == this.data[prevr][c]) {//否则,如果r位置c列的值等于prevr位置的值
                    //将r位置c列的值*2
                    this.data[r][c] *= 2;
                    this.score += this.data[r][c];
                    //将prevr位置c列置为0
                    this.data[prevr][c] = 0;
                }
            }
        }
    },
    getPrevInCol(r, c) {
        //循环,r到>=0结束,每次递减1
        for (var i = r - 1; i >= 0; i--) {
            //如果r位置c列不等于0, 就返回r
            if (this.data[i][c] != 0) return i;
        }//(遍历结束)
        return -1; //返回-1
    },

    updateView() {//将data中的数据更新到每个div中
        //遍历二维数组
        for (var r = 0; r < this.RN; r++) {
            for (var c = 0; c < this.CN; c++) {
                var n = this.data[r][c];
                //找到id为crc的div
                var div = document.getElementById("c" + r + c);
                if (n != 0) {//如果n不是0
                    div.innerHTML = n;//设置div的内容为n
                    //设置div的class为cell n+n
                    div.className = "cell n" + n;
                } else {
                    div.innerHTML = "";//清楚div的内容
                    //恢复div的class为cell
                    div.className = "cell";
                }
            }
        }
        //找到id为score的span,设置其内容为score属性
        document.getElementById("score")
            .innerHTML = this.score;
        //找到id为gameOver的div
        var div = document.getElementById("gameOver");
        //如果游戏状态为GAMEOVER就设置div显示
        if (this.state == this.GAMEOVER) {
            div.style.display = "block";
            //找到id为final的span,设置其内容为score
            document.getElementById("final")
                .innerHTML = this.score;
        } else {//否则就设置div隐藏
            div.style.display = "none";
        }
    },
    randomNum() {//在一个随机位置生成2或4
        while (true) {//反复:
            //在0~RN-1之间生成随机数r
            var r = Math.floor(Math.random() * this.RN);
            //在0~CN-1之间生成随机数c
            var c = Math.floor(Math.random() * this.CN);
            //如果data中r行c列的值为0
            if (this.data[r][c] == 0) {
                //将data中r行c列赋值为:
                //随机生成一个小数,如果<0.5,就取2,否则取4
                this.data[r][c] = Math.random() < 0.5 ? 2 : 4;
                break; //退出循环
            }
        }
    },
}
game.start();

在功能上向左,向右,向上,向下基本一致