原生JS写的2048游戏,后又对js代码进行了精简,写了左移逻辑,其他方向采用转置矩阵后左移代码复用。代码如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>2048小游戏</title>
<link rel="stylesheet" href="2048.css">
</head>
<body>
<p>
<!--TOP:<span id="top">0</span><br>-->
SCORE:<span id="score">0</span>
</p>
<div id="playground">
<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"></span><br>
<a class="btn" οnclick="game.start()">Try again!</a>
</p>
</div>
<script src = "2048.js">
</script>
</body>
</html>
CSS:
#playground{
width: 480px; height:480px;
margin:0 auto;
background:#bbada0;
border-radius:10px;
position:relative;
}
.cell{
width:100px;
height:100px;
border-radius:6px;
background: #ccc0b3;
position:absolute;
line-height:100px;
font-size:60px;
text-align:center;
color:#fff;
}
[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{
position:absolute;
left:0;right:0;top:0;bottom:0;
background:rgba(55,55,55,.5);
}
#gameOver>p{
width:300px;
height:200px;
background:#fff;
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:#fff;
background-color:#9f8d77;
border-radius:6px;
cursor:pointer;
}
JS:
/** * Created by viyo on 2016/12/7. */ var game={ RN:4,CN:4, data:null, score:0, state:1, GAMEOVER:0, RUNNING:1, start:function(){ this.state=this.RUNNING; this.score=0; this.data=[]; for(var r=0;r<this.RN;r++){ this.data[r]=new Array(this.CN);//this.data.push([]); for(var c=0;c<this.CN;c++){ this.data[r][c]=0; } } this.randomNum(); this.randomNum(); this.updateView(); document.onkeydown = function(e){ switch(e.keyCode){ case 37: this.moveLeft();break; case 38: this.moveTop();break; case 39: this.moveRight();break; case 40: this.moveDown();break; } }.bind(this); //用onkeydown外的this替换内部的this console.log(this.data.join("\n")); }, randomNum:function() //在一个随机位置生成2或4 { while (true) { var r = Math.floor(Math.random() * this.RN); var c = Math.floor(Math.random() * this.CN); if (this.data[r][c] === 0) { this.data[r][c] = Math.random() < 0.5 ? 2 : 4; break; } } }, updateView:function(){ //更新数据 for(var r=0;r<this.RN;r++){ for(var c=0;c<this.CN;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("score").innerHTML=this.score; document.getElementById("gameOver").style.display=this.state===this.GAMEOVER?"block":"none"; this.state===this.GAMEOVER&&( document.getElementById("final").innerHTML=this.score ); }, moveLeft:function(){ var before=String(this.data); for(var r=0;r<this.RN;r++){ this.moveLeftInRow(r); } var after=String(this.data); if(after!=before){ this.randomNum(); this.isGameOver()&&(this.state=this.GAMEOVER); this.updateView(); } }, moveLeftInRow:function(r){ //左移1行 for(var c=0;c<this.CN-1;c++){ //c从0开始,遍历data中r行,到<CN-1结束 var nextc=this.getNextInRow(r,c); //找data中r行c列右侧下一个不为0的位置nextc if(nextc==-1){break;} //如果nextc是-1,就退出循环 else{ //否则 if(this.data[r][c]==0){ //如果r行c列为0 this.data[r][c]=this.data[r][nextc]; //将r行nextc列的值赋值给r行c列 this.data[r][nextc]=0; //将r行nextc列的值置为0 c--; //c留在原地 }else if(this.data[r][c]==this.data[r][nextc]){ //否则,如果r行c列等于r行nextc列 this.data[r][c]*=2; //将r行c列的值*2 this.score+=this.data[r][c]; //将r行c列的新值累加到score属性上 this.data[r][nextc]=0; //将r行nextc列的值置为0 } } } }, getNextInRow:function(r,c){ for(var i=c+1;i<this.CN;i++){ if(this.data[r][i]!=0) return i; } return -1; }, moveRight:function(){ this.xExchangge(); this.moveLeft(); this.xExchangge(); this.updateView(); }, moveTop:function(){ this.middleExchange(); this.moveLeft(); this.middleExchange(); this.updateView(); }, moveDown:function(){ this.middleExchange(); this.moveRight(); this.middleExchange(); this.updateView(); }, xExchangge:function(){ for(var i=0;i<4;i++){ for(var j=0;j<2;j++){ this.data[i][j]^=this.data[i][3-j]; this.data[i][3-j]^=this.data[i][j]; this.data[i][j]^=this.data[i][3-j]; } } }, middleExchange:function(){ for(var i=0;i<4;i++){ for(var j=i+1;j<4;j++){ this.data[i][j]^=this.data[j][i]; this.data[j][i]^=this.data[i][j]; this.data[i][j]^=this.data[j][i]; } } }, isGameOver:function(){ for(var r=0;r<this.RN;r++){ for(var c=0;c<this.CN;c++){ //如果当前元素是0或c<this.CN-1且当前元素等于右侧元素或r<this.RN-1且当前元素等于下方元素 if(this.data[r][c]==0|| c<this.CN-1 &&this.data[r][c]==this.data[r][c+1]|| r<this.RN-1 &&this.data[r][c]==this.data[r+1][c]){ return false; } } } return true; } }; game.start();