JQuery實現1024小游戲


最近用Jqery寫了一個1024小游戲,由於是第一次寫小游戲,所以就選了一個基礎的沒什么難度游戲。具體實現如下:

首先在開發時將整個游戲分成兩層(自認為),底層是游戲的數據結構以及對數據的操作,上層是顯示出來的用戶界面。底層選擇使用一個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>&nbsp;&nbsp;&nbsp;&nbsp;最高分:<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;/*設置 h1、h2、h3、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循環進行設置:

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 }

不同的數字顯示不同的背景顏色與文字顏色:

 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禁止鍵盤操作。

①游戲初始化

初始化封裝成一個函數方便后續的【開始新的游戲】以及【再玩一次】功能。

 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,在每次操作后若游戲沒結束,會在一個空的位置隨機生成一個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即可。

 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后需要將其繪制出來:

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 });

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM