【Game】2048小游戏

  每个男孩都有一个游戏梦吧,本例简单讲述一款很火的游戏《2048》的制作。

  本例参考地址:https://www.imooc.com/learn/76

 游戏准备

  1、游戏的逻辑(2048大家去玩一玩就知道逻辑了)

  2、制作技术:Html,Css,Javascript,Jquery

  3、美术

游戏架构

  

游戏代码

  html代码:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8">
 5     <title>2048</title>
 6     <link rel="stylesheet" type="text/css" href="css/index.css">
 7     <script type="text/javascript" src="lib/jquery/jquery.min.js"></script>
 8     <script type="text/javascript" src="js/support.js"></script>
 9     <script type="text/javascript" src="js/animation.js"></script>
10     <script type="text/javascript" src="js/index.js"></script>
11 </head>
12 <body>
13     <!-- 头部 -->
14     <header>
15         <h1>2048</h1>
16         <a href="javascript:newgame();" id="newgamebutton">New Game</a>
17         <p>score:<span id="score">0</span></p>
18     </header>
19     
20     <section id="grid-container">
21         <div class="grid-cell" id="grid-cell-0-0"></div>
22         <div class="grid-cell" id="grid-cell-0-1"></div>
23         <div class="grid-cell" id="grid-cell-0-2"></div>
24         <div class="grid-cell" id="grid-cell-0-3"></div>
25         <div class="grid-cell" id="grid-cell-1-0"></div>
26         <div class="grid-cell" id="grid-cell-1-1"></div>
27         <div class="grid-cell" id="grid-cell-1-2"></div>
28         <div class="grid-cell" id="grid-cell-1-3"></div>
29         <div class="grid-cell" id="grid-cell-2-0"></div>
30         <div class="grid-cell" id="grid-cell-2-1"></div>
31         <div class="grid-cell" id="grid-cell-2-2"></div>
32         <div class="grid-cell" id="grid-cell-2-3"></div>
33         <div class="grid-cell" id="grid-cell-3-0"></div>
34         <div class="grid-cell" id="grid-cell-3-1"></div>
35         <div class="grid-cell" id="grid-cell-3-2"></div>
36         <div class="grid-cell" id="grid-cell-3-3"></div>
37 
38     </section>
39 </body>
40 </html>

  css代码:

 1 /*头部*/
 2 header {
 3     margin: 0 auto;
 4     width: 500px;
 5     text-align: center;
 6 }
 7 
 8 header h1 {
 9     font-family: Arial;
10     font-size: 60px;
11     font-weight: bold;
12 }
13 
14 header #newgamebutton {
15     display: block;
16     margin: 20px auto;
17 
18     width: 100px;
19     padding: 10px;
20     background-color: #8f7a66;
21 
22     font-family: Arial;
23     color: white;
24     border-radius: 10px;
25     text-decoration: none;
26 }
27 
28 header #newgamebutton:hover {
29     background-color: #9f8b77;
30 }
31 
32 header p {
33     font-family: Arial;
34     font-size: 25px;
35     margin: 20px auto;
36 }
37 
38 /*格子*/
39 #grid-container {
40     width: 460px;
41     height: 460px;
42     padding: 20px;
43 
44     margin: 50px auto;
45     background-color: #bbada0;
46 
47     border-radius: 10px;
48     position: relative;
49 }
50 #grid-container .grid-cell {
51     width: 100px;
52     height: 100px;
53     border-radius: 6px;
54     background-color: #ccc0b3;
55 
56     position: absolute;
57 }
58 
59 #grid-container .number-cell {
60     border-radius: 6px;
61 
62     font-family: Arial;
63     font-weight: bold;
64     font-size: 60px;
65     line-height: 100px;
66     text-align: center;
67 
68     position: absolute;
69 }

  js部分

  底层js:

  1 /* 底层支持js */
  2 
  3 //获取格子距离顶部的距离
  4 function getPosTop(i, j) {
  5     return 20 + i * 120;
  6 }
  7 //获取格子距离左边的距离
  8 function getPosLeft(i, j) {
  9     return 20 + j * 120;
 10 }
 11 
 12 //获取格子背景色
 13 function getNumberBackgroundColor(number) {
 14     switch (number) {
 15         case 2:
 16             return "#eee4da";
 17             break;
 18         case 4:
 19             return "#ede0c8";
 20             break;
 21         case 8:
 22             return "#f2b179";
 23             break;
 24         case 16:
 25             return "#f59563";
 26             break;
 27         case 32:
 28             return "#f67c5f";
 29             break;
 30         case 64:
 31             return "#f65e3b";
 32             break;
 33         case 128:
 34             return "#edcf72";
 35             break;
 36         case 256:
 37             return "#edcc61";
 38             break;
 39         case 512:
 40             return "#9c0";
 41             break;
 42         case 1024:
 43             return "#33b5e5";
 44             break;
 45         case 2048:
 46             return "#09c";
 47             break;
 48         case 4096:
 49             return "#s6c";
 50             break;
 51         case 8192:
 52             return "#93c";
 53             break;
 54     }
 55     return "black";
 56 }
 57 
 58 //获取格子文字色
 59 function getNumberColor(number) {
 60     if (number <= 4) {
 61         return "#776e65";
 62     }
 63     return "white";
 64 }
 65 
 66 // 判断格子是否有无空余
 67 function nospace(board) {
 68     for (var row = 0; row < 4; row++) {
 69         for (var col = 0; col < 4; col++) {
 70             if (board[row][col] == 0) {
 71                 return false;
 72             }
 73         }
 74     }
 75     return true;
 76 }
 77 
 78 
 79 
 80 //判断能否左移
 81 function canMoveLeft(board) {
 82     for (var i = 0; i < 4; i++) {
 83         
 84         for (var j = 1; j < 4; j++) {
 85             if (board[i][j] != 0) {
 86 
 87                 if (board[i][j-1] == 0 || board[i][j-1] == board[i][j]) {
 88                     // 左侧格子空 或 左侧盒子等于自己
 89                     return true;
 90                 }
 91             }
 92         }
 93     }
 94     return false;
 95 }
 96 
 97 function canMoveRight(board) {
 98     for (var i = 0; i < 4; i++) {
 99         for (var j = 2; j >= 0; j--) {
100             if (board[i][j] != 0) {
101                 if (board[i][j+1] == 0 || board[i][j+1] == board[i][j]) {
102                     
103                     return true;
104                 }
105             }
106         }
107     }
108     return false;
109 }
110 
111 //判断能否上移
112 function canMoveUp(board) {
113     for (var j = 0; j < 4; j++) {
114         for (var i = 1; i < 4; i++) {
115             if (board[i][j] != 0) {
116                 if (board[i-1][j] == 0 || board[i-1][j] == board[i][j]) {
117                     
118                     return true;
119                 }
120             }
121         }
122     }
123     return false;
124 }
125 
126 
127 
128 
129 function canMoveDown(board) {
130     for (var j = 0; j < 4; j++) {
131         for (var i = 2; i >= 0; i--) {
132             if (board[i][j] != 0) {
133                 if (board[i+1][j] == 0 || board[i+1][j] == board[i][j]) {
134          
135                     return true;
136                 }
137             }
138         }
139     }
140     return false;
141 }
142 
143 
144 
145 
146 // 判断水平方向上是否有障碍物
147 function noBlockHorizontal(row, col1, col2, board) {
148     for (var i = col1 + 1; i < col2; i++) {
149         if(board[row][i] != 0){
150             return false;
151         }
152     }
153     return true;
154 }
155 
156 // 判断垂直方向是否有障碍物
157 function noBlockVertical(col, row1, row2, board) {
158     for (var i = row1 + 1; i < row2; i++) {
159         if(board[i][col] != 0){
160             return false;
161         }
162     }
163     return true;
164 }
165 
166 
167 function nomove(board) {
168     if(canMoveLeft(board) 
169         || canMoveRight(board)
170         || canMoveUp(board)
171         || canMoveDown(board))
172         return false;
173     return true;
174 }

  动画js:

// 显示随机数字
function showNumberWithAnimation(randx, randy, randNumber) {
    var numberCell = $("#number-cell-" + randx + "-" + randy);
    numberCell.css("background-color", getNumberBackgroundColor(randNumber));
    numberCell.css("color", getNumberColor(randNumber));
    numberCell.text(randNumber);

    numberCell.animate({
         "100px",
        height: "100px",
        top: getPosTop(randx, randy),
        left: getPosLeft(randx, randy)
    }, 50);
}


// 显示移动动画
function showMoveAnimation(fromx, fromy, tox, toy){
    var numberCell = $("#number-cell-" + fromx + "-" + fromy);
    numberCell.animate({
        top: getPosTop(tox, toy),
        left: getPosLeft(tox, toy)
    },200);
}


function updateScore(score) {
    $("#score").text(score);
}

  逻辑js:

  1 var board = new Array();//全局二维数组
  2 var score = 0;//全局分数
  3 var hasConflicted = new Array();//全局碰撞二维数组
  4 
  5 //入口
  6 $(document).ready(function() {
  7     newgame();
  8 });
  9 
 10 
 11 //新游戏 
 12 function newgame() {
 13     // 初始化棋盘格
 14     init();
 15     // 在随机两个各自生成数字
 16     generateOneNumber();
 17     generateOneNumber();
 18 }
 19 
 20 // 初始化棋盘格
 21 function init() {
 22 
 23     // 初始位子
 24     for (var i = 0; i < 4; i++) {
 25         for (var j = 0; j < 4; j++) {
 26             var gridCell = $("#grid-cell-" + i + "-" + j);
 27             gridCell.css("top", getPosTop(i, j));
 28             gridCell.css("left", getPosLeft(i, j));
 29         }
 30     }
 31 
 32     // 初始值
 33     for (var i = 0; i < 4; i++) {
 34         board[i] = new Array();
 35         hasConflicted[i] = new Array();
 36         for (var j = 0; j < 4; j++) {
 37             board[i][j] = 0;
 38             hasConflicted[i][j] = false;
 39         }
 40     }
 41 
 42     // 更新界面显示
 43     updateBoardView();
 44 
 45     score = 0;
 46     updateScore(score);
 47 
 48 }
 49 
 50 // 更新界面显示
 51 function updateBoardView() {
 52     // 移除已有值的元素
 53     $(".number-cell").remove();
 54 
 55     for (var i = 0; i < 4; i++) {
 56         for (var j = 0; j < 4; j++) {
 57             $("#grid-container").append("<div class='number-cell' id='number-cell-" + i + "-" + j + "'></div>");
 58             var theNumberCell = $("#number-cell-" + i + "-" + j);
 59 
 60             if (board[i][j] == 0) {
 61                 theNumberCell.css("width", "0px");
 62                 theNumberCell.css("height", "0px");
 63                 theNumberCell.css("top", getPosTop(i, j) + 50);
 64                 theNumberCell.css("left", getPosLeft(i, j) + 50);
 65             } else {
 66                 theNumberCell.css("width", "100px");
 67                 theNumberCell.css("height", "100px");
 68                 theNumberCell.css("top", getPosTop(i, j));
 69                 theNumberCell.css("left", getPosLeft(i, j));
 70                 theNumberCell.css("background-color", getNumberBackgroundColor(board[i][j]));
 71                 theNumberCell.css("color", getNumberColor(board[i][j]));
 72                 theNumberCell.text(board[i][j]);
 73                 
 74                 
 75             }
 76             hasConflicted[i][j] = false;
 77         }
 78     }
 79 }
 80 
 81 // 随机在格子中生成一个数
 82 function generateOneNumber() {
 83 
 84     // 判断格子空间
 85     if (nospace(board)) {
 86         return false;
 87     }
 88 
 89     // 随机一个位子
 90 
 91     var randx = 0;
 92     var randy = 0;
 93     do {
 94         randx = parseInt(Math.floor(Math.random() * 4));
 95         randy = parseInt(Math.floor(Math.random() * 4));
 96         if (board[randx][randy] == 0) break;
 97     }
 98     while(true);
 99 
100     // 随机一个数
101     var randNumber = Math.random() < 0.5 ? 2 : 4 ;
102 
103     // 在随机位子显示随机数
104     board[randx][randy] = randNumber;
105     showNumberWithAnimation(randx, randy, randNumber);
106 
107     return true;
108 
109 
110 }
111 
112 
113 
114 // 添加操作事件
115 $(document).keydown(function(event){
116     switch(event.keyCode) {
117         case 37: // left
118             if(moveLeft()) {
119                 setTimeout("generateOneNumber()", 210);
120                 setTimeout("isgameover()", 300);
121             }
122             console.log(board);
123             break;
124         case 38: // up
125             if(moveUp()) {
126                 setTimeout("generateOneNumber()", 210);
127                 setTimeout("isgameover()", 300);
128             }
129             break;
130         case 39: // right
131             if(moveRight()) {
132                 setTimeout("generateOneNumber()", 210);
133                 setTimeout("isgameover()", 300);
134             }
135             break;
136         case 40: // down
137             if(moveDown()) {
138                 setTimeout("generateOneNumber()", 210);
139                 setTimeout("isgameover()", 300);
140             }
141             break;
142         default: break;
143     }
144     return false;
145 });
146 
147 function isgameover(){
148     if(nospace(board) && nomove(board)) {
149         gameover();
150     }
151 }
152 
153 function gameover(){
154     alert("gameover");
155 }
156 
157 // 左移
158 function moveLeft() {
159     // 判断能否左移
160     if(!canMoveLeft(board)) {
161         return false;
162     }
163 
164     for (var row = 0; row < 4; row++) {
165         for (var col = 1; col < 4; col++) {
166             if(board[row][col] != 0) {
167                 
168                 for (var k = 0; k < col; k++) {
169                     // 左侧为0
170                     if(board[row][k] == 0 && noBlockHorizontal(row, k, col, board)){
171                         // move
172                         showMoveAnimation(row, col, row, k);
173                         board[row][k] = board[row][col];
174                         board[row][col] = 0;
175                         continue;
176                     }
177                     // 左侧等于自己
178                     else if (board[row][ k] == board[row][col] && noBlockHorizontal(row, k, col, board) && !hasConflicted[row][k])
179                     {
180                         // move
181                         showMoveAnimation(row, col, row, k);
182 
183                         // add
184                         board[row][k] += board[row][col];
185                         board[row][col] = 0;
186 
187                         score += board[row][k];
188                         updateScore(score);
189 
190                         hasConflicted[row][k] = true;
191 
192                         continue;
193                     }
194                 }
195             }
196         }
197     }
198     
199     setTimeout("updateBoardView()", 200);
200     return true;
201 }
202 
203 
204 // 右移
205 function moveRight() {
206     // 判断能否右移
207     if(!canMoveRight(board)) {
208         return false;
209     }
210 
211     for (var row = 0; row < 4; row++) {
212         for (var col = 2; col >= 0; col--) {
213             if(board[row][col] != 0) {
214                 
215                 for (var k = 3;  k > col; k--) {
216                     
217                     if(board[row][k] == 0 && noBlockHorizontal(row, col, k, board)){
218                         // move
219                         showMoveAnimation(row, col, row, k);
220                         board[row][k] = board[row][col];
221                         board[row][col] = 0;
222                         continue;
223                     }
224                     
225                     else if (board[row][k] == board[row][col] && noBlockHorizontal(row, col, k, board) && !hasConflicted[row][k])
226                     {
227                         // move
228                         showMoveAnimation(row, col, row, k);
229 
230                         // add
231                         board[row][k] += board[row][col];
232                         board[row][col] = 0;
233 
234                         score += board[row][k];
235                         updateScore(score);
236 
237                         hasConflicted[row][k] = true;
238 
239                         continue;
240                     }
241                 }
242             }
243         }
244     }
245     
246     setTimeout("updateBoardView()", 200);
247     return true;
248 }
249 
250 
251 
252 // 上移
253 function moveUp() {
254     // 判断能否上移
255     if(!canMoveUp(board)) {
256         return false;
257     }
258 
259     for (var col = 0; col < 4; col++) {
260         for (var row = 1; row < 4; row++) {
261         
262             if(board[row][col] != 0) {
263                 
264                 for (var k = 0; k < row; k++) {
265                     
266                     if(board[k][col] == 0 && noBlockVertical(col, k, row, board)){
267                         // move
268                         showMoveAnimation(row, col, k, col);
269                         board[k][col] = board[row][col];
270                         board[row][col] = 0;
271                         continue;
272                     }
273                     
274                     else if (board[k][col] == board[row][col] && noBlockVertical(col, k, row, board) && !hasConflicted[k][col])
275                     {
276                         // move
277                         showMoveAnimation(row, col, k, col);
278 
279                         // add
280                         board[k][col] += board[row][col];
281                         board[row][col] = 0;
282 
283                         score += board[k][col];
284                         updateScore(score);
285 
286                         hasConflicted[k][col] = true;
287 
288                         continue;
289                     }
290                 }
291             }
292         }
293     }
294     
295     setTimeout("updateBoardView()", 200);
296     return true;
297 }
298 
299 
300 
301 
302 // 下移
303 function moveDown() {
304     // 判断能否下移
305     if(!canMoveDown(board)) {
306         return false;
307     }
308 
309     for (var col = 0; col < 4; col++) {
310     
311         for (var row = 2; row >= 0; row--) {
312             if(board[row][col] != 0) {
313                 
314                 for (var k = 3;  k > row; k--) {
315                     
316                     if(board[k][col] == 0 && noBlockVertical(col, row, k, board)){
317                         // move
318                         showMoveAnimation(row, col, k, col);
319                         board[k][col] = board[row][col];
320                         board[row][col] = 0;
321                         continue;
322                     }
323                     
324                     else if (board[k][col] == board[row][col] && noBlockVertical(col, row, k, board) && !hasConflicted[k][col])
325                     {
326                         // move
327                         showMoveAnimation(row, col, k, col);
328 
329                         // add
330                         board[k][col] += board[row][col];
331                         board[row][col] = 0;
332 
333                         score += board[k][col]
334                         updateScore(score);
335 
336                         hasConflicted[k][col] = true;
337                         continue;
338                     }
339                 }
340             }
341         }
342     }
343     
344     setTimeout("updateBoardView()", 200);
345     return true;
346 }

游戏展示

  普通版地址:http://naughty7878.top/game/2048

  优化版地址:http://naughty7878.top/game/2048plus

游戏优化

  1、随机数的参数,怎么更加准确的找空空位,在随机空位中产生随机数

  2、增加分数时,增加动画。

  3、游戏结束时,动画结束

  4、私人定制游戏,显示时:2-->小白,4-->实习生,8 -->程序猿,16-->项目经理

  5、操作问题,怎么鼠标操作,触摸滑动操作 

  6、设备适配的问题,兼容手机等。

  

原文地址:https://www.cnblogs.com/h--d/p/8168795.html