#gridPanel{
width:480px; height:480px;
margin:0 auto;
background-color:#bbada0;
border-radius:10px;
position:relative;
}
.grid,.cell{
width:100px; height:100px;
border-radius:6px;
}
.grid{
float:left;
margin:16px 0 0 16px;
background-color:#ccc0b3;
}
.cell{
text-align:center;
line-height:100px;
color:#776e65;
font-size:60px;
position:absolute;
}
/*每行拥有相同的top*/
/*每列拥有相同的left*/
#c00,#c01,#c02,#c03{top:16px; }
#c00,#c10,#c20,#c30{left:16px; }
#c10,#c11,#c12,#c13{top:132px; }
#c01,#c11,#c21,#c31{left:132px;}
#c20,#c21,#c22,#c23{top:248px; }
#c02,#c12,#c22,#c32{left:248px;}
#c30,#c31,#c32,#c33{top:364px; }
#c03,#c13,#c23,#c33{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}
/*显示分数的p元素*/
p{width:480px; margin:0 auto;
font-family:Arial; font-weight:bold;
font-size:40px; padding-top:15px;
}
/*GameOver界面样式*/
#gameOver{display:none;
width:100%; height:100%;
position:absolute; top:0px; left:0px;
}
#gameOver div{width:100%; height:100%;
background-color:#555; opacity:0.5;
}
#gameOver p{border-radius:10px;
position:absolute;top:200px;left:35%;
width:300px; height:200px;
border:1px solid #edcf72;
line-height:1.6em;
text-align:center;
background-color:#fff;
}
.button{padding:10px; border-radius:6px;
background-color:#9f8b77;
color:#fff; cursor:pointer;
}
function Task(obj,topStep,leftStep){
this.obj=obj;
this.topStep=topStep;
this.leftStep=leftStep;
}
//moveStep方法将当前元素对象移动一步
Task.prototype.moveStep=function(){
var style=getComputedStyle(this.obj,null);
var top=parseInt(style.top);
var left=parseInt(style.left);
this.obj.style.top=top+this.topStep+"px";
this.obj.style.left=left+this.leftStep+"px";
}
//清楚元素对象的样式,使其返回原地
Task.prototype.clear=function(){
this.obj.style.left="";
this.obj.style.top="";
}
var animation={
times:10,//每个动画10步完成
interval:10,//200毫秒迈一步
timer:null,//保存定时器id的属性
tasks:[],//保存每次需要移动的任务
addTask:function(source,target){
//00 02
console.log(source+","+target);
var sourceDiv=
document.getElementById("c"+source);
var targetDiv=
document.getElementById("c"+target);
var sourceStyle=getComputedStyle(sourceDiv);
var targetStyle=getComputedStyle(targetDiv);
var topStep=(parseInt(targetStyle.top)-
parseInt(sourceStyle.top))/this.times;
var leftStep=(parseInt(targetStyle.left)-
parseInt(sourceStyle.left))/this.times;
var task=new Task(sourceDiv,topStep,leftStep);
this.tasks.push(task);
},
start:function(){
this.timer=setInterval(function(){
for(var i=0;i animation.tasks[i].moveStep(); } animation.times--; if(animation.times==0){ for(var i=0;i animation.tasks[i].clear(); } clearInterval(animation.timer); animation.timer=null; animation.tasks=[]; animation.times=10; } },this.interval); } } var game={ data:[], score:0, state:1, RUNNING:1, GAME_OVER:0, PLAYING:2,//动画正在播放中 start:function(){ this.data=[[0,0,0,0],[0,0,0,0], [0,0,0,0],[0,0,0,0]]; this.score=0; this.state=this.RUNNING; var div=document.getElementById("gameOver"); //修改div的style.display div.style.display="none"; this.randomNum(); this.randomNum(); this.updateView(); }, isFull:function(){ for(var row=0;row<4;row++){ for(var col=0;col<4;col++){ if(this.data[row][col]==0){ return false; } } } return true; }, randomNum:function(){ if(this.isFull()){ return; } while(true){ var row=Math.floor(Math.random()*4); var col=Math.floor(Math.random()*4); if(this.data[row][col]==0){ this.data[row][col]= Math.random()<0.5?2:4; break; } } }, canLeft:function(){ //遍历每个元素(最左侧列除外) for(var row=0;row<4;row++){ for(var col=1;col<4;col++){ // 只要发现任意元素左侧值==0或 // 当前值==左侧值 if(this.data[row][col]!=0){ if(this.data[row][col-1]==0|| this.data[row][col-1]==this.data[row][col]){ return true; } } } }//如果循环正常结束, return false; }, moveLeft:function(){ if(this.canLeft()){//先判断能否左移 for(var row=0;row<4;row++){ this.moveLeftInRow(row); } this.state=this.PLAYING; animation.start(); setTimeout(function(){ game.state=game.RUNNING; game.randomNum(); game.updateView(); },animation.times*animation.interval); } }, moveLeftInRow:function(row){ for(var col=0;col<=2;col++){ var nextCol=this.getNextRight(row,col); if(nextCol==-1){ break; }else{ if(this.data[row][col]==0){ this.data[row][col]= this.data[row][nextCol]; this.data[row][nextCol]=0; animation.addTask(""+row+nextCol,""+row+col); col--; }else if(this.data[row][col] ==this.data[row][nextCol]){ this.data[row][col]*=2; this.score+=this.data[row][col]; this.data[row][nextCol]=0; animation.addTask(""+row+nextCol,""+row+col); } } } }, getNextRight:function(row,col){ for(var i=col+1;i<4;i++){ if(this.data[row][i]!=0){ return i; } } return -1; }, /*将游戏数据整体更新到页面上*/ updateView:function(){ //Step1:遍历二维数组中每个元素 for(var row=0;row<4;row++){ for(var col=0;col<4;col++){ //Step2:找到和当前元素对应的div // 拼div的id: c+row+col var div=document.getElementById("c"+row+col); //Step3:将当前元素的值放入div中 // div.innerHTML=? // 如果当前值==0,放入"" // 否则放入当前值 div.innerHTML=this.data[row][col]==0?"": this.data[row][col]; //Step4: 根据当前元素值修改div样式类 // div.className="类名"; // 如果当前值==0,className="cell" // 否则className="cell n"+当前值 div.className=this.data[row][col]==0?"cell": "cell n"+this.data[row][col]; } } /*将分数放入span*/ var span=document.getElementById("score"); span.innerHTML=this.score; /*判断游戏结束*/ if(this.isGameOver()){ this.state=this.GAME_OVER; //显示游戏结束div //找到gameOverdiv var div=document.getElementById("gameOver"); var finalScore= document.getElementById("finalScore"); finalScore.innerHTML=this.score; //显示div div.style.display="block"; } }, canRight:function(){/*判断能否右移*/ for(var row=0;row<4;row++){ for(var col=0;col<3;col++){ if(this.data[row][col]!=0){ if(this.data[row][col+1]==0|| this.data[row][col]==this.data[row][col+1]){ return true; } } } }return false; }, moveRight:function(){/*向右移动所有行*/ if(this.canRight()){ for(var row=0;row<4;row++){ this.moveRightInRow(row); } this.state=this.PLAYING; animation.start(); setTimeout(function(){ game.state=game.RUNNING; game.randomNum(); game.updateView(); },animation.times*animation.interval); } }, moveRightInRow:function(row){/*右移当前行*/ //从右向左遍历检查,(最左边元素除外) for(var col=3;col>0;col--){ var nextCol=this.getNextLeft(row,col); if(nextCol==-1){break; }else{ if(this.data[row][col]==0){ this.data[row][col]=this.data[row][nextCol]; this.data[row][nextCol]=0; animation.addTask(""+row+nextCol,""+row+col); col++; }else if(this.data[row][col] ==this.data[row][nextCol]){ this.data[row][col]*=2; this.score+=this.data[row][col]; this.data[row][nextCol]=0; animation.addTask(""+row+nextCol,""+row+col); } } } }, getNextLeft:function(row,col){ //从当前位置向左,找下一个不为0的数 for(var i=col-1;i>=0;i--){ if(this.data[row][i]!=0){ return i; } }return -1; }, canUp:function(){ for(var row=1;row<4;row++){ for(var col=0;col<4;col++){ if(this.data[row][col]!=0){ if(this.data[row-1][col]==0|| this.data[row][col]==this.data[row-1][col]){ return true; } } } }return false; }, moveUp:function(){ if(this.canUp()){ for(var col=0;col<4;col++){ this.moveUpInCol(col); } this.state=this.PLAYING; animation.start(); setTimeout(function(){ game.state=game.RUNNING; game.randomNum(); game.updateView(); },animation.times*animation.interval); } }, moveUpInCol:function(col){ for(var row=0;row<3;row++){ var nextRow=this.getNextDown(row,col); if(nextRow==-1){ break; }else{ if(this.data[row][col]==0){ this.data[row][col]=this.data[nextRow][col]; this.data[nextRow][col]=0; animation.addTask(""+nextRow+col,""+row+col); row--; }else if(this.data[row][col]== this.data[nextRow][col]){ this.data[row][col]*=2; this.score+=this.data[row][col]; this.data[nextRow][col]=0; animation.addTask(""+nextRow+col,""+row+col); } } } }, getNextDown:function(row,col){ for(var i=row+1;i<4;i++){ if(this.data[i][col]!=0){ return i; } }return -1; }, canDown:function(){ for(var row=0;row<3;row++){ for(var col=0;col<4;col++){ if(this.data[row][col]!=0){ if(this.data[row+1][col]==0|| this.data[row][col]==this.data[row+1][col]){ return true; } } } }return false; }, moveDown:function(){ if(this.canDown()){ for(var col=0;col<4;col++){ this.moveDownInCol(col); } this.state=this.PLAYING; animation.start(); setTimeout(function(){ game.state=game.RUNNING; game.randomNum(); game.updateView(); },animation.times*animation.interval); } }, moveDownInCol:function(col){ for(var row=3;row>0;row--){ var nextRow=this.getNextUp(row,col); if(nextRow==-1){break; }else{ if(this.data[row][col]==0){ this.data[row][col]=this.data[nextRow][col]; this.data[nextRow][col]=0; animation.addTask(""+nextRow+col,""+row+col); row++; }else if(this.data[row][col]== this.data[nextRow][col]){ this.data[row][col]*=2; this.score+=this.data[row][col]; this.data[nextRow][col]=0; animation.addTask(""+nextRow+col,""+row+col); } } } }, getNextUp:function(row,col){ for(var i=row-1;i>=0;i--){ if(this.data[i][col]!=0){ return i; } }return -1; }, isGameOver:function(){/*判断游戏是否结束*/ for(var row=0;row<4;row++){ for(var col=0;col<4;col++){ if(this.data[row][col]==0){ return false; } if(col<3){/*检查右侧相邻*/ if(this.data[row][col]==this.data[row][col+1]){ return false; } } if(row<3){/*检查下方相邻*/ if(this.data[row][col]==this.data[row+1][col]){ return false; } } } }return true; } } window.onload=function(){ game.start(); document.onkeydown=function(){ if(game.state!=game.PLAYING){ var event=window.event||arguments[0]; if(game.state==game.RUNNING){ if(event.keyCode==37){ game.moveLeft(); }else if(event.keyCode==39){ game.moveRight(); }else if(event.keyCode==38){ game.moveUp(); }else if(event.keyCode==40){ game.moveDown(); } }else if(event.keyCode==13){ game.start(); } } } } Score: