实现的效果图
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();