最近用Jqery寫了一個1024小遊戲,因爲是第一次寫小遊戲,因此就選了一個基礎的沒什麼難度遊戲。具體實現以下:css
首先在開發時將整個遊戲分紅兩層(自認爲),底層是遊戲的數據結構以及對數據的操做,上層是顯示出來的用戶界面。底層選擇使用一個4x4的二維數組,整個遊戲的數據操做都圍繞着這個二維數組進行。數組
1 <div id="game"> 2 <div id="header"> 3 <h1>1024</h1> 4 <button id="newGame">開始新的遊戲</button> 5 <p>分數:<span id="score">0</span> 最高分:<span id="maxScore">0</span></p> 6 <div id="movescore"><p>+16</p></div> 7 </div> 8 <div id="container"> 9 <div class="cell" id="cell-0-0"></div> 10 <div class="cell" id="cell-0-1"></div> 11 <div class="cell" id="cell-0-2"></div> 12 <div class="cell" id="cell-0-3"></div> 13 <div class="cell" id="cell-1-0"></div> 14 <div class="cell" id="cell-1-1"></div> 15 <div class="cell" id="cell-1-2"></div> 16 <div class="cell" id="cell-1-3"></div> 17 <div class="cell" id="cell-2-0"></div> 18 <div class="cell" id="cell-2-1"></div> 19 <div class="cell" id="cell-2-2"></div> 20 <div class="cell" id="cell-2-3"></div> 21 <div class="cell" id="cell-3-0"></div> 22 <div class="cell" id="cell-3-1"></div> 23 <div class="cell" id="cell-3-2"></div> 24 <div class="cell" id="cell-3-3"></div> 25 </div> 26 <div class="gameover"> 27 <div id="gameoverText"> 28 <p></p> 29 </div> 30 <p id="gameoverScore"></p> 31 <div id="reStart"> 32 <button id="reStartBtn">再玩一次</button> 33 </div> 34 </div> 35 </div>
CSS:數據結構
1 *{ 2 margin: 0; 3 padding: 0; 4 } 5 #game{ 6 font-family: Arial; 7 margin: 0 auto; 8 text-align: center; 9 } 10 #header{ 11 margin: 20px; 12 } 13 #header a{ 14 font-family: Arial; 15 text-decoration: none;/*設置 h一、h二、h三、h4 元素的文本修飾*/ 16 display: block; 17 color: white; 18 margin: 20px auto; 19 width: 125px; 20 height: 35px; 21 text-align: center; 22 line-height: 40px; 23 background-color: #8f7a66; 24 border-radius: 10px; 25 font-size: 15px; 26 } 27 #header p{ 28 font-family: Arial; 29 font-size: 20px; 30 } 31 #container{ 32 width: 460px; 33 height: 460px; 34 background-color: #bbada0; 35 margin: 0 auto; 36 border-radius: 10px; 37 position: relative; 38 padding: 20px; 39 } 40 .cell{ 41 width: 100px; 42 height: 100px; 43 border-radius: 6px; 44 background-color: #ccc0b3; 45 position: absolute; 46 font-size: 3.5em; 47 font-weight:700; 48 text-align: center; 49 line-height:100px; 50 } 51 #newGame{ 52 width: 120px; 53 height: 30px; 54 border-radius: 5px; 55 border: 1px solid rgb(143,122,102); 56 background-color: rgb(143,122,102); 57 color: white; 58 margin-top: 10px; 59 margin-bottom: 10px; 60 } 61 .gameover{ 62 width: 100%; 63 height: 500px; 64 background-color: rgba(255,255,255,0.5); 65 position: absolute; 66 top:153px; 67 display: none; 68 } 69 #gameoverText{ 70 font-size: 4em; 71 font-weight: 600; 72 color: #363636; 73 text-align: center; 74 opacity: 1; 75 padding-top: 10%; 76 } 77 #reStartBtn{ 78 width: 100px; 79 height: 40px; 80 border-radius: 5px; 81 border: 1px solid rgb(143,122,102); 82 background-color: rgb(143,122,102); 83 color: white; 84 margin-top: 3%; 85 } 86 #gameoverScore{ 87 font-size: 1.5em; 88 } 89 #movescore{ 90 position: absolute; 91 text-align: center; 92 padding-left: 45%; 93 top:110px; 94 font-weight: 600; 95 display: none; 96 }
此時界面的16個格子是重疊在一塊兒的,給每一個格子寫css比較麻煩,因此經過js循環進行設置:dom
1 //初始化繪製表格 2 function printTab(){ 3 for(var i=0;i<4;i++){ 4 for(var j=0;j<4;j++){ 5 var cell=$('#cell-'+i+'-'+j); 6 cell.css({top:(20+i*120),left:(20+j*120)}); 7 } 8 } 9 }
不一樣的數字顯示不一樣的背景顏色與文字顏色:ide
1 function getBackgroundColor(number){ 2 switch (number) { 3 case 2:return "#eee4da";break; 4 case 4:return "#ede0c8";break; 5 case 8:return "#f2b179";break; 6 case 16:return "#f59563";break; 7 case 32:return "#f67c5f";break; 8 case 64:return "#f65e3b";break; 9 case 128:return "#edcf72";break; 10 case 256:return "#edcc61";break; 11 case 512:return "#9c0";break; 12 case 1024:return "#33b5e5";break; 13 case 2048:return "#09c";break; 14 case 4096:return "#a6c";break; 15 case 8192:return "#93c";break; 16 } 17 } 18 // 設置相應數字的文字顏色 19 function getColor(number){ 20 if (number <= 4) { 21 return "#776e65" 22 } 23 return "white"; 24 }
每次操做後根據當前二維數組進行重繪畫面:函數
1 //根據二維數組繪製畫面 2 function rePrint(checkerboard){ 3 for(var i=0;i<4;i++){ 4 for(var j=0;j<4;j++){ 5 if(checkerboard[i][j]!=0){ 6 var printCell=$('#cell-'+i+'-'+j); 7 printCell.css('background-color',getBackgroundColor(checkerboard[i][j])); 8 printCell.css('color',getColor(checkerboard[i][j])); 9 printCell.text(checkerboard[i][j]); 10 if(checkerboard[i][j]>=1024){ 11 printCell.css('font-size','2.5em'); 12 printCell.css('font-weight','500'); 13 } 14 }else{ 15 var printCell=$('#cell-'+i+'-'+j); 16 printCell.css('background-color','#ccc0b3'); 17 printCell.css('color','black'); 18 printCell.text(''); 19 } 20 } 21 } 22 }
除了須要定義一個二維數組checkerboard,還須要定義一個存總分的變量score,一個存每次操做得分的變量addScore,一個記錄鍵盤是否能夠操做的變量ableKeyDown,0能夠響應鍵盤操做,1禁止鍵盤操做。動畫
初始化封裝成一個函數方便後續的【開始新的遊戲】以及【再玩一次】功能。spa
1 //初始化遊戲 2 function newgame(){ 3 ableKeyDown=0; 4 score=0; 5 checkerboard=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]; 6 $('#score').text('0'); 7 $('#maxScore').text(window.localStorage.getItem("maxScore")); 8 rePrint(checkerboard); 9 randNum(checkerboard); 10 randNum(checkerboard); 11 }
根據遊戲規則,在遊戲剛開始時會在兩個隨即位置分別生成2或4,在每次操做後若遊戲沒結束,會在一個空的位置隨機生成一個2或4,將這一功能封裝成一個函數,Math.random()生成的隨機數範圍是[0,1),因爲二維數組範圍是[0,3],因此經過Math.floor(Math.random()*4)將獲得0-3的隨機數。另外須要隨機獲得2或4,定義一個數組initRandNum=[2,4],只需隨機獲得initRandNum[0]或initRandNum[1]便可,因此同理使用Math.floor(Math.random()*2)隨機獲得1或2便可。code
1 function randNum(checkerboard){//在隨機位置隨機產生2或4 2 var randX = Math.floor(Math.random()*4); 3 var randY = Math.floor(Math.random()*4); 4 var initRandNum=[2,4]; 5 var randNum=Math.floor(Math.random()*2); 6 var randVal=initRandNum[randNum]; 7 while(true){ 8 if(checkerboard[randX][randY]==0){ 9 break; 10 }else{ 11 var randX = Math.floor(Math.random()*4); 12 var randY = Math.floor(Math.random()*4); 13 } 14 } 15 checkerboard[randX][randY]=randVal; 16 printRandNum(randX,randY,randVal);//將randNum()繪製出來 17 }
在獲得上述隨即位置的2或4後須要將其繪製出來:blog
1 function printRandNum(randX,randY,randVal){ 2 var printRandCell=$('#cell-'+randX+'-'+randY); 3 printRandCell.css('background-color',getBackgroundColor(randVal)); 4 printRandCell.css('color',getColor(randVal)); 5 printRandCell.text(randVal); 6 }
即判斷當前可否移動的函數以及如何移動合併的函數。
1)--------判斷可否移動,以左移爲例
根據對遊戲的觀察發如今兩中狀況下能夠移動,一是存在某個不爲零的方塊,該數字左邊爲空,即其左邊的數組值爲0;二是存在某個不爲零的方塊,,該數字左邊與其相同,即其左邊的數組值與其相等。對二維數組進行循環,若知足上述條件就返回1,便可以移動。
1 function canMoveLeft(checkerboard){ 2 for(var i=0;i<4;i++){ 3 for(var j=0;j<4;j++){ 4 if(checkerboard[i][j]!=0){ 5 if(j!=0){ 6 if(checkerboard[i][j-1]==0||checkerboard[i][j-1]==checkerboard[i][j]){ 7 return 1; 8 break; 9 } 10 } 11 } 12 } 13 } 14 }
2)--------移動合併函數,以左移爲例
這個應該是遊戲中最重要的函數,根據遊戲規則,1)若一個非零方塊左邊所有爲空,它將移動到最左邊,若左邊的某個不爲0,它將移動到這個不爲0方塊的右邊;2)若一個非零方塊與左邊的數字相同,它將移動到左邊並與之合併相加;3)若一個非零方塊與左邊的數字相同,他與左邊合併後的值恰巧與再左邊的數相同,此時應該只進行第一次合併,不進行第二次合併。例如當前一排是4,2,2,0,其移動後結果應該是4,4,0,0,而不是8,0,0,0。
第三點尤其重要,最開始因爲忽略了這點寫出來後結果是不對的。我真對3)的解決辦法是,在每次循環一行時初始化一個長度爲4的數組var tag=[0,0,0,0],若某個數在這次循環制相加過一次,就在tag相應位置置爲1,再而後在每次合併前作一次判斷,若該tag爲1,則不進行相加。
1 function moveLeft(checkerboard){ 2 addscore=0; 3 for(var i=0;i<4;i++){ 4 var tag=[0,0,0,0]; 5 for(var j=1;j<4;j++){ 7 if(checkerboard[i][j]!=0){ 8 if(checkerboard[i][j-1]==0){//左邊爲空時 9 for(k=j-1;k>=0;k--){ 10 if(checkerboard[i][k]!=0){ 11 checkerboard[i][k+1]=checkerboard[i][j]; 12 checkerboard[i][j]=0; 13 if(checkerboard[i][k+1]==checkerboard[i][k]){//移動後與左邊相等 14 if(tag[k]==0&&tag[k+1]==0){ 15 checkerboard[i][k]+=checkerboard[i][k+1]; 16 score += checkerboard[i][k]; 17 addscore+=checkerboard[i][k]; 18 tag[k]=1;20 checkerboard[i][k+1]=0; 21 } 22 } 23 break; 24 }else if(k==0){//左邊全空 25 checkerboard[i][0]=checkerboard[i][j]; 26 checkerboard[i][j]=0; 27 break; 28 } 29 } 30 }else if(checkerboard[i][j-1]==checkerboard[i][j]){//左邊相等時 31 if(tag[j-1]==0&&tag[j]==0){ 32 checkerboard[i][j-1]+=checkerboard[i][j]; 33 score += checkerboard[i][j-1]; 34 addscore+=checkerboard[i][j-1]; 35 tag[j-i]=1;37 checkerboard[i][j]=0; 38 } 39 } 40 } 41 } 42 } 43 rePrint(checkerboard);//中止移動後重繪畫面 44 }
值得注意的是,爲了計算遊戲的總分以及每次操做的得分,須要在每次合併後對addScore和score進行計算。
右移、上移、下移與左移邏輯基本相同,只需對左移代碼稍做修改便可。
1 //更新分數 2 function updateScore(num){ 3 $('#score').text(num); 4 }
在每次得分後會在總分位置產生一個加分動畫
1 //分數動畫 2 function movescore(score){ 3 if(score>0){ 4 $('#movescore p').text('+'+score); 5 $('#movescore').css('top','110px'); 6 $('#movescore').show(); 7 var top; 8 var topVal=110; 9 var opacityVal=1; 10 var timer=null; 11 timer=setInterval(function(){ 12 topVal-=5; 13 opacityVal-=0.1; 14 top=topVal+'px'; 15 $('#movescore').css('top',top); 16 $('#movescore').css('opacity',opacityVal); 17 if(topVal<50){ 18 clearInterval(timer); 19 $('#movescore').hide(); 20 } 21 },40); 22 } 23 }
若二維數組中某一項等於1024遊戲結束,顯示最終得分,並設置鍵盤不可繼續操做;或者當前沒法繼續移動遊戲結束,顯示最終得分。
1 //遊戲結束函數 2 function gameOver(checkerboard){ 3 if(canMoveLeft(checkerboard)!=1&&canMoveRight(checkerboard)!=1&&canMoveUp(checkerboard)!=1&&canMoveDown(checkerboard)!=1){ 4 $('.gameover').show(); 5 $('#gameoverText p').text('Game Over !'); 6 $('#gameoverScore').text('最終得分'+score); 7 if(score>window.localStorage.getItem("maxScore")){ 8 window.localStorage.setItem("maxScore",score); 9 $('#maxScore').text(window.localStorage.getItem("maxScore")); 10 } 11 } 12 for(var i=0;i<4;i++){ 13 for(var j=0;j<4;j++){ 14 if(checkerboard[i][j]==1024){ 15 ableKeyDown=1;//鍵盤不可操做 16 $('.gameover').show(); 17 $('#gameoverText p').text('Congratulations!'); 18 $('#gameoverScore').text('最終得分'+score); 19 if(score>window.localStorage.getItem("maxScore")){ 20 window.localStorage.setItem("maxScore",score); 21 $('#maxScore').text(window.localStorage.getItem("maxScore")); 22 } 23 break; 24 } 25 } 26 } 27 }
1 //開始新遊戲 2 $('#newGame').click(function(){ 3 newgame(); 4 }); 5 //再玩一次 6 $('#reStartBtn').click(function(){ 7 $('.gameover').hide(); 8 newgame(); 9 });