2048小游戏

实现的效果图

1.游戏开始

2.游戏结束

HTML页面

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <link rel="stylesheet" href="2048.css" />
    </head>
    <body>
        <div class="header">
            SCORE:<span id="score1"></span><br />
        </div>
        <div id=grid>
            <!--第一行-->
            <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 class="gameover" id="gameover">
            <p>
                GAME OVER!<br />
                SCORE:<span class="finalscore" id="final">0</span><br>
                <a href="javascript:game.strt()" class="try">TRY AGAIN</a>
            </p>
        </div>
        <script src="2048.js"></script>
    </body>
</html>

CSS页面

#grid{
     480px;
    height: 480px;
    margin: 0 auto;    
    position: relative;
    background-color: #bbada0;
    border-radius: 15px;
}
.cell{
     100px;
    height: 100px;
    background-color: #ccc0b3;
    position: absolute;
    text-align: center;
    font-size: 60px;
    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}
.n8,.n16,.n32,.n64,.n128,.n256,.n512,.n1024,.n2048,.n4096,.n8192{color:#fff}
.n1024,.n2048,.n4096,.n8192{font-size:40px}

.header{    
    height: 50px;
     480px;
    color: #00000;
    margin: 0 auto;
    font-size: 40px;
    font-weight: bold;
    margin-bottom: 20px;    
}

#gameover{
    position: absolute;
    background-color: rgba(50,50,50,0.5);
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    color: #8f7b63;
}
.gameover>p{
     300px;
    height: 200px;
    background-color: #fff;
    border: 1px solid #edcf72;
    border-radius: 15px;
    position: absolute;
    left: 50%;
    top: 50%;
    margin-top: -100px;
    margin-left: -150px;
    font-size: 30px;
    font-weight: bold;
    text-align: center;
    line-height:1.5em;
    padding-top:50px ;
}
.try{
    display: block;
     200px;
    height: 50px;
    border-radius: 8px;
    background-color: #8f7b63;
    position: absolute;
    left:50px;
    color: #fff5e9;
    text-decoration: none;
}
.gameover>p span{
    color: #f00;
    font-size: 40px;
}
#score1{
    color: #f00;
    font-size:40px;
}

JS页面

var game={
    date:null,//建立一个空的二维数组
    RN:4,//每一行
    CN:4,//
    score:0,//分数
    state:1,//保存运行中的状态 1表示运行中 0表示结束
    RUNNING:1,//运行中的状态
    GAMEOVER:0,//结束状态

    strt(){//开始游戏    
        //将遮罩层隐藏 开始游戏之前清理遮罩层
        document.getElementById("gameover").style.display="none";
        //设置游戏状态  重置游戏为运行中
        this.state=this.RUNNING;
        //游戏开始时分数清零
        this.score = 0; 
        //新建空数组date
        this.date=[];
        //r从0开始,到RN结束
        for(var r=0;r<this.RN;r++){
            this.date[r]=[];
            //c从0开始,到CN结束
            for(var c=0;c<this.CN;c++){
                //设置date中r行c列的值为0
                this.date[r][c]=0
            }            
        }
        this.randomNum();
        this.randomNum();
        this.updateView();
        console.log(this.date.join("
"));    
        document.onkeydown=function(event){
            switch(event.keyCode){
                case 37://左移                    
                    game.moveLeft();  
                    break;
                case 38://上移                    
                    game.moveTop();                
                    break;
                case 39://右移    
                    game.moveRight();
                    break;
                case 40://下移
                    game.moveDown();
                    break;
            }
        }
    },    
    randomNum(){ //随机一个数字     
        while(true){
            //在0~RN-1之间生成随机数r
            r = Math.floor(Math.random() *this.RN);
            //在0~CN-1之间生成随机数c
            c = Math.floor(Math.random() *this.CN); 
            //如果
            if(this.date[r][c]==0){
                this.date[r][c] = (Math.random() < 0.5) ? 2 : 4; 
                //-console.log(this.date[r][c]);
                 break;
            }                               
            }
    },
    updateView(){
        //将date中数据更新到每一个div中,修改div中数字的同时,修改div样式
        for(var r=0;r<this.RN;r++ ){//遍历二维数组
            for(var c=0;c<this.CN;c++){
                //将date中r行c列中的数字获取存储在变量n中
                var n=this.date[r][c];
                //找到id为'c'rc的div
                var div=document.getElementById("c"+r+c);
                if(n==0){//如果n等于0 div中的数字清空  恢复div的class为cell
                    div.innerHTML="";   
                    div.className="cell";
                }else{//如果不等于0 设置div中的数字为n
                    div.innerHTML=n;
                    div.className="cell n"+n;
                }
            }
        } //二维数组遍历结束
        //将分数显示在页面中
        //通过id找到score的span,设置其内容为score属性
        document.getElementById("score1").innerHTML = this.score;
        this.state=this.isgameover()?this.GAMEOVER:this.RUNNING;
        var div= document.getElementById("gameover");
        //根据游戏状态判断游戏是否结束,并且判断gameover是否显示
         if(this.state == this.GAMEOVER){
             //显示gameover 找到final的span  设置内容为score
             div.style.display="block";
             document.getElementById("final").innerHTML=this.score;
         }else{
             //否则隐藏gameover的div
             div.style.display="none";
         }
    },
    isgameover(){ //判断游戏是否结束
        //遍历date
        for(var r = 0;r<this.RN;r++){
            for(var c = 0;c<this.CN;c++){
                if(game.date[r][c] == 0){   //如果有等于零的情况,则游戏继续
                    return false;
                }
                if(c<this.RN-1){//检测同一行之间是否有相同
                    if(game.date[r][c] == game.date[r][c+1]){
                        return false;
                    }
                }
                if(r<this.CN-1){//检测同一列之间是否有相同
                    if(game.date[r][c] == game.date[r+1][c]){
                        return false;
                    }
                }
            }
        }
        return true;//如果条件全都不满足,表示游戏结束
    },
//左移开始
    moveLeft(){//左移所有行
        // 为数组拍照保存到before中
        var before=String(this.date);
        // r从0开始,到<RN结束
        for(var r=0;r<this.RN;r++){
            // 左移第r行  moveLeftInRow(r) ---- 可以单独完成一件事情  反复被使用
            this.moveLeftInRow(r);
        }// 循环结束                    
        // 为数组拍照保存到after中
        var after=String(this.date);
        // 如果after!=before   表示data中的数据有变化
        if(after!=before){
            // 生成随机数添加到data中去   randomNum()
            this.randomNum();
            // 更新页面 updateView()
            document.getElementById("gameover").style.display = "none";
            this.updateView();
        }
        
    },
    moveLeftInRow(r){//左移第r行
        // c从0开始,到<CN-1
        for(var c=0;c<this.CN-1;c++){
            // 查找r行c列下一个不为0的位置nextc   调用一个函数  var nextc = getNextInRow(r,c)
            var nextc =this.getNextInRow(r,c);
            // 如果nextc=-1  
            if(nextc == -1){
                break;//没有找到  退出循环
            }else{
                // 否则
                if(this.date[r][c] == 0){// 如果c位置的值等于0
                    // 将r行nextc位置的值赋值给c位置
                    this.date[r][c] = this.date[r][nextc];
                    // 将nectc位置的值赋值为0
                    this.date[r][nextc]=0;
                    // 将c留在原地   看后面是否有和c位置值相等的数据
                    c--;
                }else if(this.date[r][c] == this.date[r][nextc]){
                    // 否则,如果c位置的值等于nextc位置的值
                    // 将c位置的值*2
                    this.date[r][c]*=2;    
                    this.score += this.date[r][c];
                    // 将nextc位置的值设置为0
                    this.date[r][nextc]=0;
                }
            }                                    
        }            
    },
    getNextInRow(r,c){
        //查找r行c列下一个不为0的位置
        // i从c+1开始,到<CN结束
        for(var i=c+1;i<this.CN;i++){            
            // 如果i位置的值不为0, return  i
            if(this.date[r][i] != 0){
                return i;// 循环结束                
            }
        }        
        return -1;// 返回 -1 表示没有找到不为0 的位置
    },
//左移结束
//右移开始
    moveRight(){
        // 为数组拍照保存到before中
        var before=String(this.date);
        // r从0开始,到<RN结束
        for(var r=0;r<this.RN;r++){
            // 左移第r行  moveRightInRow(r)---- 可以单独完成一件事情  反复被使用
            this.moveRightInRow(r);
        }// 循环结束                    
        // 为数组拍照保存到after中
        var after=String(this.date);
        // 如果before!= after     表示data中的数据有变化
        if(before!= after){
            // 生成随机数添加到data中去   randomNum()
            this.randomNum();
            // 更新页面 updateView()s
            this.updateView();
        }        
    },
    moveRightInRow(r){//右移第r行
        //c从倒数第二个开始,到>0结束    反向遍历r行每一列
        for(var c=this.RN-1;c>0;c--){
            // 查询r行c列的前一个不为0的位置    等到位置prevc  调用函数 getPrevcInRow(r,c)
                var prevc = this.getPrevcInRow(r,c)
                //若prevc == -1
                if (prevc == -1) {
                    break;
                }else{
                    //如果c位置的值等于0
                        if(this.date[r][c] == 0){
                            // 将prevc位置的值赋值给c位置
                            this.date[r][c] = this.date[r][prevc];
                                // 将prevc位置的值赋值为0
                            this.date[r][prevc] = 0;
                                // 将c留在原地   看后面是否有和c位置值相等的数据
                                c++;
                        }else if (this.date[r][c] == this.date[r][prevc]) {
                            // 否则,如果c位置的值等于prevc位置的值
                            // 将c位置的值*2
                            this.date[r][c] *= 2;
                            this.score += this.date[r][c];
                            // 将prevc位置的值设置为0
                            this.date[r][prevc] = 0;
                        }
                }
        }
    },
    getPrevcInRow(r,c){//获取r行c列前一个不为0值的位置
        // i从CN-1开始,到i>=0结束
        for (var i =c-1;i>=0;i--) {
            // 如果i位置的值不为0, return  i
                if (this.date[r][i] != 0) {
                        return i;// 循环结束                
                }
        }
        return -1;
    },
//右移结束
//上移开始
    moveTop(){
        // 为数组拍照保存到before中
        var before=String(this.date);
        // c从0开始,到<RN结束
        for(var c=0;c<this.CN;c++){
            // 左移第r行  moveTopInRow(c) ---- 可以单独完成一件事情  反复被使用
            this.moveTopInRow(c);
        }// 循环结束                    
        // 为数组拍照保存到after中
        var after=String(this.date);
        // 如果after!=before   表示data中的数据有变化
        if(after!=before){
            // 生成随机数添加到data中去   randomNum()
            this.randomNum();
            // 更新页面 updateView()
            this.updateView();
        }        
    },
    moveTopInRow(c){
        for(var r= 0;r<this.RN;r++){
            // 查找c行r列下一个不为0的位置nextr   调用一个函数  var nextr =getNextrInRow(r,c);
                var nextr = this.getNextrInRow(r,c);
                //若nextr != -1
                if (nextr != -1) {
                    //如果c位置的值等于0
                        if(this.date[r][c] == 0){
                            // 将nextc位置的值赋值给c位置
                            this.date[r][c] = this.date[nextr][c];
                                // 将nextr位置的值赋值为0
                            this.date[nextr][c]= 0;
                                // 将r留在原地   看后面是否有和c位置值相等的数据
                                r--;
                        }else if (this.date[r][c] == this.date[nextr][c]) {
                            // 否则,如果c位置的值等于nextz位置的值
                            // 将c位置的值*2
                            this.date[r][c] *= 2;
                        this.score += this.date[r][c];
                            // 将nextz位置的值设置为0
                            this.date[nextr][c]= 0;
                        }
                }
        }
    },
    getNextrInRow(r,c){
        //查找c行r列下一个不为0的位置
        // i从r+1开始,到i<RN结束
        for (var i = r+1;i<this.RN;i++) {
            // 如果i位置的值不为0, return  i
                if(this.date[i][c] != 0) {
                        return i;// 循环结束                
                }
        }
        return -1;
    },
//上移结束
//下移开始
    moveDown(){
        // 为数组拍照保存到before中
        var before=String(this.date);
        // c从0开始,到<RN结束
        for(var c=0;c<this.CN;c++){
            // 左移第r行  moveDownInRowSS(c) ---- 可以单独完成一件事情  反复被使用
            this.moveDownInRow(c);
        }// 循环结束                    
        // 为数组拍照保存到after中
        var after=String(this.date);
        // 如果after!=before   表示data中的数据有变化
        if(before != after){
            // 生成随机数添加到data中去   randomNum()
            this.randomNum();
            // 更新页面 updateView()
            this.updateView();
        }        
    },
    
    moveDownInRow(c){
        for(var r=this.CN-1;r>0;r--){
            // 查询r行c列的前一个不为0的位置    等到位置prevd  调用函数 getPrevdInRow(r,c)
                var prevd = this.getPrevdInRow(r,c)
                //若prevd = -1
                if (prevd ==-1) {
                    break;
                }
                else{
                    //如果c位置的值等于0
                        if(this.date[r][c] == 0){
                            // 将prevd位置的值赋值给c位置
                            this.date[r][c] = this.date[prevd][c];
                                // 将prevd位置的值赋值为0
                            this.date[prevd][c] = 0;
                                // 将c留在原地   看后面是否有和c位置值相等的数据
                                r++;
                        }else if (this.date[r][c] == this.date[prevd][c]) {
                            // 否则,如果c位置的值等于prevd位置的值
                            // 将c位置的值*2
                            this.date[r][c]*= 2;
                            this.score += this.date[r][c];
                            // 将prevd位置的值设置为0
                            this.date[prevd][c] = 0;
                        }
                }
        }
    },
    getPrevdInRow(r,c){
        //查找c行r列下一个不为0的位置
        // i从r-1开始,到i>=0结束
        for (var i= r-1;i>=0;i--) {
            // 如果i位置的值不为0, return  i
                if(this.date[i][c] != 0) {
                        return i;// 循环结束                
                }
        }
        return -1;
    },
}
game.strt();
原文地址:https://www.cnblogs.com/conlover/p/10944600.html