新手写的,可能不是很完善,欢迎修改及探讨
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>2048游戏</title> 6 <style> 7 .container{ 8 width: 600px; 9 height: 600px; 10 border: 2px solid #000; 11 background-color: white; 12 margin: auto; 13 } 14 15 .header{ 16 font: bold 40px arial; 17 margin-left: 80px; 18 } 19 .header span, #gameOver span{ 20 color: red; 21 } 22 23 #gameBody{ 24 width: 450px; 25 height: 450px; 26 margin-left: 80px; 27 padding: 5px 0 0 5px; 28 border-radius: 10px; 29 background-color: #bbada0; 30 } 31 32 .cell{ 33 width: 100px; 34 height: 100px; 35 margin: 5px; 36 background-color: #ccc0b3; 37 border-radius: 5px; 38 float: left; 39 font: 50px/100px arial; 40 text-align: center; 41 } 42 43 .n2{background-color: #eee3da} 44 .n4{background-color: #ede0c8} 45 .n8{background-color: #f2b179} 46 .n16{background-color: #f59563} 47 .n32{background-color: #f67c5f} 48 .n64{background-color: #f65e3b} 49 .n128{background-color: #edcf72} 50 .n256{background-color: #edcc61} 51 .n512{background-color: #9c0} 52 .n1024{background-color: #33b5e5} 53 .n2048{background-color: #09c} 54 .n4096{background-color: #a6c} 55 .n8192{background-color: #93c} 56 .n2,.n4{color: #776e65} 57 .n1024,.n2048,.n4096,.n8192{font-size: 40px} 58 59 60 #gameOver{ 61 display: none; 62 position: absolute; 63 top: 0; 64 left: 0; 65 right: 0; 66 bottom: 0; 67 background:rgba(55,55,55,0.5); 68 } 69 70 #gameOver p{ 71 width: 300px; 72 height: 200px; 73 position: absolute; 74 top: 50%; 75 left: 50%; 76 margin: -100px 0 0 -150px; 77 text-align: center; 78 border-radius: 10px; 79 border: 1px solid #edcf72; 80 font: bold 40px/65px arial; 81 background: #fff; 82 } 83 84 #gameOver .btn{ 85 padding: 10px; 86 color:#fff; 87 background: #9f8d77; 88 border-radius: 6px; 89 text-decoration: none; 90 } 91 </style> 92 </head> 93 <body> 94 <div class="container"> 95 <p class="header">SCORE:<span id="score">0</span></p> 96 <div id="gameBody"> 97 <div class="cell" id="cell-00"></div> 98 <div class="cell" id="cell-01"></div> 99 <div class="cell" id="cell-02"></div> 100 <div class="cell" id="cell-03"></div> 101 <div class="cell" id="cell-10"></div> 102 <div class="cell" id="cell-11"></div> 103 <div class="cell" id="cell-12"></div> 104 <div class="cell" id="cell-13"></div> 105 <div class="cell" id="cell-20"></div> 106 <div class="cell" id="cell-21"></div> 107 <div class="cell" id="cell-22"></div> 108 <div class="cell" id="cell-23"></div> 109 <div class="cell" id="cell-30"></div> 110 <div class="cell" id="cell-31"></div> 111 <div class="cell" id="cell-32"></div> 112 <div class="cell" id="cell-33"></div> 113 </div> 114 <div id="gameOver"> 115 <p> 116 GAME OVER<br> 117 SCORE:<span id="final">0</span><br> 118 <a href="javascript:game.start();" class="btn">TRY AGAIN!</a> 119 </p> 120 </div> 121 </div> 122 123 <script> 124 //创建对象:属性+方法 125 var game = { 126 //数组,保存数据 127 data:[], 128 //游戏得分:0 129 score:0, 130 //设置游戏状态:1-开始,0-结束 131 state:1, 132 //游戏状态:开始 133 RUNNING:1, 134 //游戏状态:结束 135 GAMEOVER:0, 136 137 //游戏开始start()方法 138 start:function(){ 139 //设置游戏状态为开始 140 this.state=this.RUNNING; 141 //初始化游戏得分为0 142 this.score=0; 143 //创建一个二维数组 144 for(var r = 0; r < 4; r++){ 145 //创建一个一维数组, 146 var datacell = []; 147 //将一维数组值初始化为0 148 for(var c = 0;c < 4; c++){ 149 datacell[c] = 0; 150 } 151 //将一维数组的值循环赋给数组data[],成功创建一个二维数组 152 this.data[r] = datacell; 153 } 154 155 //调用函数随机生成两个数 156 this.randomNum(); 157 this.randomNum(); 158 //刷新页面,显示div的值 159 this.updateView(); 160 }, 161 162 //随机生成两个数4或2 163 randomNum:function(){ 164 while(true){ 165 var r=Math.floor(Math.random()*this.data.length); 166 var c=Math.floor(Math.random()*this.data.length); 167 if(this.data[r][c]==0){ 168 //随机生成2和4的概率相等 169 this.data[r][c]=Math.random()<0.5?2:4; 170 break; 171 } 172 } 173 }, 174 175 updateView:function(){ 176 for(var r=0;r<this.data.length;r++){ 177 for(var c=0;c<this.data.length;c++){ 178 //判断数组中的数据,为0则不做任何操作,保持原来数据和类名不变 179 //动态获取标签的id:要求取id名时与数组下角标相对应 180 if(this.data[r][c]==0){ 181 document.getElementById("cell-"+r+c).innerHTML=""; 182 document.getElementById("cell-"+r+c).className="cell"; 183 }else{ 184 //不为0,则将数组中数据显示在对应的div格子中 185 document.getElementById("cell-"+r+c).innerHTML= this.data[r][c]; 186 //保持原来类名不变,并追加对应div类名(动态) 187 document.getElementById("cell-"+r+c).className="cell n" + this.data[r][c]; 188 189 } 190 } 191 } 192 //将分数显示在界面上方 193 document.getElementById("score").innerHTML=this.score; 194 var gameOver=document.getElementById("gameOver"); 195 if(this.state==this.GAMEOVER){ 196 //如果状态为GAMEOVER(即0,表示游戏结束,显示结束界面,并将最后分数显示在结束界面 197 gameOver.style.display="block"; 198 document.getElementById("final").innerHTML=this.score; 199 }else{ 200 //如果状态为1,表示游戏还未结束,隐藏结束界面 201 gameOver.style.display="none"; 202 } 203 }, 204 205 //向左移动所有行 206 moveLeft:function(){ 207 //判断字符串是否移动 208 //做移动操作前先将数组转换为字符串保存 209 var before=String(this.data); 210 //遍历行 211 for(var r=0;r<this.data.length;r++){ 212 this.moveLeftRow(r); 213 } 214 //做移动操作后先将数组转换为字符串保存 215 var after=String(this.data); 216 //将移动操作前后的数组(字符串)作比较,如果不相等,即发生改变,则随机生成一个数 217 if(before!=after){ 218 this.randomNum(); 219 //随机生成一个数后,判断游戏是否结束,设置游戏状态 220 if(this.isGameOver()){ 221 this.state=this.GAMEOVER; 222 } 223 //游戏未结束刷新页面,再显示随机生成数 224 this.updateView(); 225 } 226 }, 227 228 //判断并向左移动指定行中的每个元素 229 moveLeftRow:function(r){ 230 //0开始,遍历r行中每一个元素 231 for(var c=0;c<this.data.length-1;c++){ 232 //获得当前元素下一个不为0的元素的下标nextc 233 var nextc=this.getNextRow(r,c) 234 //如果nextc=-1,说明右侧没有元素了,退出循环 235 if(nextc==-1) { 236 break; 237 }else if(this.data[r][c]==0){ //如果自己==0 则将下一个位置放入当前位置,下一个位置设置为零 238 this.data[r][c]=this.data[r][nextc]; 239 this.data[r][nextc]=0; 240 //重新检查 241 c--; 242 }else if(this.data[r][c]==this.data[r][nextc]){// 如果当前位置的值==nextc的位置的值,将当前位置*=2;下一个位置设置为0 243 this.data[r][c]*=2; 244 //将当前值累加到score属性上 245 this.score+=this.data[r][c]; 246 this.data[r][nextc]=0; 247 } 248 } 249 }, 250 251 //找当前位置右侧,下一个不为0的数 252 getNextRow:function(r,c){ 253 //从c+1 遍历row行中剩余元素, 254 for(var i=c+1;i<this.data.length;i++){ 255 //如果出现不为0的值,返回它的列数 256 if(this.data[r][i]!=0) { 257 return i; 258 } 259 } 260 //循环退出返回-1 261 return -1; 262 }, 263 264 265 //向右移动所有行 266 moveRight:function(){ 267 var before=String(this.data); 268 for(var r=0;r<this.data.length;r++){ 269 this.moveRightRow(r); 270 } 271 var after=String(this.data); 272 if(before!=after){ 273 this.randomNum(); 274 if(this.isGameOver()){ 275 this.state=this.GAMEOVER; 276 } 277 this.updateView(); 278 } 279 }, 280 281 moveRightRow:function(r){ 282 for(var c=this.data.length-1;c>0;c--){ 283 var prec=this.getPreRow(r,c) 284 if(prec==-1){ 285 break; 286 }else if(this.data[r][c]==0){ 287 this.data[r][c]=this.data[r][prec]; 288 this.data[r][prec]=0; 289 c++; 290 }else if(this.data[r][c]==this.data[r][prec]){ 291 this.data[r][c]*=2; 292 this.score+=this.data[r][c]; 293 this.data[r][prec]=0; 294 } 295 } 296 }, 297 298 getPreRow:function(r,c){ 299 for(var i=c-1;i>=0;i--){ 300 if(this.data[r][i]!=0) return i; 301 } 302 return -1; 303 }, 304 305 moveUp:function(){ 306 var before=String(this.data); 307 for(var c=0;c<this.data.length;c++){ 308 this.moveUpCol(c); 309 } 310 var after=String(this.data); 311 if(before!=after){ 312 this.randomNum(); 313 if(this.isGameOver()){ 314 this.state=this.GAMEOVER; 315 } 316 this.updateView(); 317 } 318 }, 319 320 //向上移动所有列 321 moveUpCol:function(c){ 322 for(var r=0;r<this.data.length-1;r++){ 323 var nextr=this.getNextCol(r,c) 324 if(nextr==-1) {break; 325 }else if(this.data[r][c]==0){ 326 this.data[r][c]=this.data[nextr][c]; 327 this.data[nextr][c]=0; 328 r--; 329 }else if(this.data[r][c]==this.data[nextr][c]){ 330 this.data[r][c]*=2; 331 this.score+=this.data[r][c]; 332 this.data[nextr][c]=0; 333 } 334 } 335 }, 336 337 getNextCol:function(r,c){ 338 for(var i=r+1;i<this.data.length;i++){ 339 if(this.data[i][c]!=0) return i; 340 } 341 return -1; 342 }, 343 344 //向下移动所有列 345 moveDown:function(){ 346 var before=String(this.data); 347 for(var c=0;c<this.data.length;c++){ 348 this.moveDownCol(c); 349 } 350 var after=String(this.data); 351 if(before!=after){ 352 this.randomNum(); 353 if(this.isGameOver()){ 354 this.state=this.GAMEOVER; 355 } 356 this.updateView(); 357 } 358 }, 359 360 moveDownCol:function(c){ 361 for(var r=this.data.length-1;r>0;r--){ 362 var prer=this.getPreCol(r,c) 363 if(prer==-1) { 364 break; 365 } 366 else if(this.data[r][c]==0){ 367 this.data[r][c]=this.data[prer][c]; 368 this.data[prer][c]=0; 369 r++; 370 }else if(this.data[r][c]==this.data[prer][c]){ 371 this.data[r][c]*=2; 372 this.score+=this.data[r][c]; 373 this.data[prer][c]=0; 374 } 375 } 376 }, 377 378 getPreCol:function(r,c){ 379 for(var i=r-1;i>=0;i--){ 380 if(this.data[i][c]!=0) return i; 381 } 382 return -1; 383 }, 384 385 isGameOver:function(){ 386 //游戏结束条件: 387 //1.数组中所有数据均不为0; 388 //2.数组中每一行数据相邻位置值不相等 389 //3.数组中每一列数据相邻位置值不相等 390 for(var c=0;c<this.data.length;c++){ 391 for(var r=0;r<this.data.length;r++){ 392 //判断所有不为0 393 if(this.data[r][c]==0){ 394 return false; 395 } 396 if(c<3){ 397 if(this.data[r][c]==this.data[r][c+1]){ 398 return false; 399 } 400 } 401 if(r<3){ 402 if(this.data[r][c]==this.data[r+1][c]){ 403 return false; 404 } 405 } 406 } 407 } 408 return true; 409 } 410 } 411 412 //调用函数开始游戏 413 game.start(); 414 document.onkeydown=function(event){ 415 //按下左键或者字母键a,向左移动 416 if(event.keyCode==37 || event.keyCode==65 ){ 417 game.moveLeft(); 418 } 419 //按下向上键或者字母键w,向上移动 420 if(event.keyCode==38 || event.keyCode==87 ){ 421 game.moveUp(); 422 } 423 //按下右键或者字母键d,向右移动 424 if(event.keyCode==39 || event.keyCode==68 ){ 425 game.moveRight(); 426 } 427 //按下向下键或者字母键s,向下移动 428 if(event.keyCode==40 || event.keyCode==83 ){ 429 game.moveDown(); 430 } 431 //按下空格键重新开始游戏 432 if(event.keyCode==32 ){ 433 game.start(); 434 } 435 436 } 437 438 </script> 439 </body> 440 </html>!