2048的制作
1、html部分
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <link rel="stylesheet" href="2048.css"/> 7 <script src="2048.js"></script> 8 </head> 9 <body> 10 <p> 11 Top:<span id="top">0</span><br> 12 Score:<span id="score">0</span> 13 </p> 14 <div id="gridPanel"> 15 <!--背景格--> 16 <!--第一行--> 17 <div id="g00" class="grid"></div> 18 <div id="g01" class="grid"></div> 19 <div id="g02" class="grid"></div> 20 <div id="g03" class="grid"></div> 21 <!--第二行--> 22 <div id="g10" class="grid"></div> 23 <div id="g11" class="grid"></div> 24 <div id="g12" class="grid"></div> 25 <div id="g13" class="grid"></div> 26 <!--第三行--> 27 <div id="g20" class="grid"></div> 28 <div id="g21" class="grid"></div> 29 <div id="g22" class="grid"></div> 30 <div id="g23" class="grid"></div> 31 <!--第四行--> 32 <div id="g30" class="grid"></div> 33 <div id="g31" class="grid"></div> 34 <div id="g32" class="grid"></div> 35 <div id="g33" class="grid"></div> 36 <!--前景格--> 37 <!--第一行--> 38 <div id="c00" class="cell"></div> 39 <div id="c01" class="cell"></div> 40 <div id="c02" class="cell"></div> 41 <div id="c03" class="cell"></div> 42 43 <div id="c10" class="cell"></div> 44 <div id="c11" class="cell"></div> 45 <div id="c12" class="cell"></div> 46 <div id="c13" class="cell"></div> 47 48 <div id="c20" class="cell"></div> 49 <div id="c21" class="cell"></div> 50 <div id="c22" class="cell"></div> 51 <div id="c23" class="cell"></div> 52 53 <div id="c30" class="cell"></div> 54 <div id="c31" class="cell"></div> 55 <div id="c32" class="cell"></div> 56 <div id="c33" class="cell"></div> 57 </div> 58 <div id="gameOver"> 59 <div><!--半透明背景--></div> 60 <p><!--前景对话框--> 61 Game Over!<br> 62 Score:<span id="final">0</span><br> 63 <a class="btn" onclick="game.start()">Try again!</a> 64 </p> 65 </div> 66 </body> 67 </html>
2、css部分
1 #gridPanel{ 2 width:480px; height:480px; 3 margin:0 auto; 4 background-color:#bbada0; 5 border-radius:10px; 6 position:relative; 7 } 8 .grid,.cell{ 9 width:100px; height:100px; border-radius:6px; 10 } 11 .grid{ 12 background-color:#ccc0b3; 13 float:left; 14 margin-left:16px; 15 margin-top:16px; 16 } 17 .cell{ 18 position:absolute; 19 font-size:60px; 20 text-align:center; 21 line-height:100px; 22 color:#fff; 23 } 24 [id^="c0"]{top:16px;} 25 [id^="c1"]{top:132px;} 26 [id^="c2"]{top:248px;} 27 [id^="c3"]{top:364px;} 28 29 .cell[id$="0"]{left:16px;} 30 .cell[id$="1"]{left:132px;} 31 .cell[id$="2"]{left:248px;} 32 .cell[id$="3"]{left:364px;} 33 34 .n2{background-color:#eee3da} 35 .n4{background-color:#ede0c8} 36 .n8{background-color:#f2b179} 37 .n16{background-color:#f59563} 38 .n32{background-color:#f67c5f} 39 .n64{background-color:#f65e3b} 40 .n128{background-color:#edcf72} 41 .n256{background-color:#edcc61} 42 .n512{background-color:#9c0} 43 .n1024{background-color:#33b5e5} 44 .n2048{background-color:#09c} 45 .n4096{background-color:#a6c} 46 .n8192{background-color:#93c} 47 .n2,.n4{color:#776e65} 48 .n1024,.n2048,.n4096,.n8192{font-size:40px} 49 50 p{ 51 width:480px; margin:0 auto; 52 font-size:40px; font-family:Arial; font-weight:bold; 53 padding-top:15px; 54 } 55 #gameOver{display:none; 56 width:100%; height:100%; 57 position:absolute; 58 top:0; left:0; 59 } 60 #gameOver>div{ 61 width:100%; height:100%; 62 background-color:#555; opacity:0.5; 63 } 64 #gameOver>p{ 65 width:300px; height:200px; 67 position:absolute; 68 top:50%; left:50%; 69 margin-left:-150px; margin-top:-100px; 70 71 background-color:#fff; 72 text-align:center; 73 line-height:1.5em; 74 border-radius:10px; 75 border:1px solid #edcf72; 76 } 77 .btn{ 78 color:#fff; background-color:#9f8d77; 79 border-radius:6px; 80 cursor:pointer; 81 padding:10px; 82 }
3、js部分
1 function getCookie(cookieName){ 2 var str=document.cookie; 3 var i=-1; 4 if((i=str.indexOf(cookieName+"="))!=-1){ 5 var start=i+cookieName.length+1; 6 var end=str.indexOf(";",start); 7 return str.slice(start,end==-1?str.length:end); 8 }else{ 9 return null; 10 } 11 } 12 function setCookie(cookieName,value){ 13 var date=new Date(); 14 date.setFullYear(date.getFullYear()+1); 15 document.cookie="="+value+";expires"+date.toGMTString(); 16 } 17 18 var game={ 19 data:null,//保存一个二维数组 20 RN:4,//总行数 21 CN:4,//总列数 22 score:0,//游戏得分 23 state:1,//游戏状态: 1是运行中,0是结束 24 RUNNING:1,//运行中 25 GAMEOVER:0,//结束 26 //强调: 对象自己的方法要使用自己的属性,必须加this 27 start:function(){//启动游戏 28 this.state=this.RUNNING;//初始化游戏状态为运行中 29 this.score=0; 30 this.data=[];//初始化当前对象的data属性为空数组 31 for(var r=0;r<this.RN;r++){//r从0开始,到<RN结束,每次增1 32 this.data.push([ ]);//向data中压入一个空数组 33 //c从0开始,到<CN结束,每次增1 34 for(var c=0;c<this.CN;c++){ 35 this.data[r][c]=0;//在data中r行c列的位置保存一个0 36 } 37 }//(遍历结束) 38 this.randomNum();//调用randomNum方法 39 this.randomNum();//再调用randomNum方法 40 this.updateView();//更新页面 41 var me=this;//留住this 42 //为当前页面绑定键盘事件: 43 document.onkeydown=function(e){//e: 事件对象 44 if(me.state==me.RUNNING){ 45 switch(e.keyCode){ 46 case 37: me.moveLeft();break; 47 case 38: me.moveUp();break; 48 case 39: me.moveRight();break; 49 case 40: me.moveDown();break; 50 } 51 } 52 }//document.onkeydown();//this->document 53 },//强调: 每个方法之间必须用逗号分隔 54 isGameOver:function(){//判断游戏是否结束 55 //遍历data中每个元素 56 for(var r=0;r<this.RN;r++){ 57 for(var c=0;c<this.CN;c++){ 58 if(this.data[r][c]==0){//如果当前元素等于0 59 return false;//返回false 60 } 61 //如果c<CN-1而且当前元素等于右侧元素 62 if(c<this.CN-1 63 &&this.data[r][c]==this.data[r][c+1]){ 64 return false;//返回false 65 } 66 //如果r<RN-1而且当前元素等于下方元素 67 if(r<this.RN-1 68 &&this.data[r][c]==this.data[r+1][c]){ 69 return false;//返回false 70 } 71 } 72 }//(遍历结束)返回true 73 return true; 74 }, 75 move:function(fun){//定义所有移动中相同的代码 76 //为data拍照,保存在before中 77 var before=String(this.data); 78 fun.call(this); 79 //为data拍照,保存在after中 80 var after=String(this.data); 81 //如果before不等于after,就随机生成数,更新页面 82 if(before!=after){ 83 this.randomNum(); 84 //如果调用isGameOver返回true 85 if(this.isGameOver()){ 86 this.state=this.GAMEOVER;//修改游戏状态为GAMEOVER 87 } 88 this.updateView(); 89 } 90 }, 91 moveDown:function(){//下移所有列 92 this.move(function(){ 93 for(var c=0;c<this.CN;c++){//遍历data中每一列 94 //调用moveUpInCol,传入c作为参数 95 this.moveDownInCol(c); 96 }//(遍历结束) 97 }); 98 }, 99 moveDownInCol:function(c){ 100 for(var r=this.RN-1;r>0;r--){ 101 var prevr=this.getPrevInCol(r,c); 102 if(prevr==-1){break;} 103 else{ 104 if(this.data[r][c]==0){ 105 this.data[r][c]=this.data[prevr][c]; 106 this.data[prevr][c]=0; 107 r++; 108 }else if(this.data[r][c]==this.data[prevr][c]){ 109 this.data[r][c]*=2; 110 this.score+=this.data[r][c]; 111 this.data[prevr][c]=0; 112 } 113 } 114 } 115 }, 116 getPrevInCol:function(r,c){ 117 for(var prevr=r-1;prevr>=0;prevr--){ 118 if(this.data[prevr][c]!=0){return prevr} 119 } 120 return -1; 121 }, 122 moveUp:function(){//上移所有列 123 this.move(function(){ 124 for(var c=0;c<this.CN;c++){//遍历data中每一列 125 //调用moveUpInCol,传入c作为参数 126 this.moveUpInCol(c); 127 }//(遍历结束) 128 }); 129 }, 130 moveUpInCol:function(c){//上移第c列 131 for(var r=0;r<this.RN-1;r++){//从上到下遍历每一行 132 //调用getNextInCol,传入参数r,c,返回值保存在nextr 133 var nextr=this.getNextInCol(r,c); 134 //如果nextr等于-1,就退出循环 135 if(nextr==-1){break;} 136 else{//否则 137 if(this.data[r][c]==0){//如果r行c列等于0 138 //将nextr行c列赋值给r行c列 139 this.data[r][c]=this.data[nextr][c]; 140 this.data[nextr][c]=0;//将nextr行c列置为0 141 r--; 142 }else if(this.data[r][c]==this.data[nextr][c]){ 143 //否则 如果r行c列等于nextr行c列 144 this.data[r][c]*=2;//将r行c列*2 145 this.score+=this.data[r][c]; 146 this.data[nextr][c]=0;//将nextr行c列置为0 147 } 148 } 149 } 150 }, 151 //查找r行c列下方下一个不等于0的位置 152 getNextInCol:function(r,c){ 153 //nextr从r+1开始,到<RN结束,每次增1 154 for(var nextr=r+1;nextr<this.RN;nextr++){ 155 //如果nextr行c列不等于0,就返回nextr 156 if(this.data[nextr][c]!=0){return nextr} 157 }//(遍历结束)就返回-1] 158 return -1; 159 }, 160 moveRight:function(){//右移所有行 161 this.move(function(){ 162 for(var r=0;r<this.RN;r++){//遍历data中每一行 163 //调用moveRightInRow,传入r作为参数 164 this.moveRightInRow(r); 165 }//(遍历结束) 166 }); 167 }, 168 moveRightInRow:function(r){//右移第r行 169 //从右向左遍历r行中每个元素,到>0结束 170 for(var c=this.CN-1;c>0;c--){ 171 //调用getPrevInRow,传入r,c作为参数,返回值保存在prevc中 172 var prevc=this.getPrevInRow(r,c); 173 //如果prevc为-1,就退出循环 174 if(prevc==-1){break;} 175 else{//否则 176 //如果data中r行c位置等于0 177 if(this.data[r][c]==0){ 178 //将data中r行prevc位置的值赋值给data中r行c位置 179 this.data[r][c]=this.data[r][prevc]; 180 //将data中r行prevc位置置为0 181 this.data[r][prevc]=0; 182 c++; 183 }else if(this.data[r][c]==this.data[r][prevc]){ 184 //否则,如果data中r行c位置等于data中r行prevc位置 185 this.data[r][c]*=2;//将data中r行c位置*2 186 this.score+=this.data[r][c]; 187 //将data中r行prevc位置置为0 188 this.data[r][prevc]=0; 189 } 190 } 191 } 192 }, 193 //查找r行c列左侧前一个不为0的位置s 194 getPrevInRow:function(r,c){ 195 //prevc从c-1开始,到>=0结束,每次减1 196 for(var prevc=c-1;prevc>=0;prevc--){ 197 //如果data中r行prevc位置不等于0 198 if(this.data[r][prevc]!=0){ 199 return prevc;//返回prevc 200 } 201 }//(遍历结束)就返回-1 202 return -1; 203 }, 204 moveLeft:function(){//左移所有行 205 this.move(function(){ 206 for(var r=0;r<this.RN;r++){ 207 //调用moveLeftInRow(r)左移第r行 208 this.moveLeftInRow(r); 209 }//(遍历结束) 210 }); 211 }, 212 moveLeftInRow:function(r){//左移第r行 213 //c从0开始,到<CN-1结束,每次增1 214 for(var c=0;c<this.CN-1;c++){ 215 //查找c位置后,下一个不为0的位置,保存在nextc中 216 var nextc=this.getNextInRow(r,c); 217 //如果nextc是-1,就退出循环 218 if(nextc==-1){break;} 219 else{//否则 220 if(this.data[r][c]==0){//如果data中r行c位置等于0 221 //将data中r行nextc位置的值赋值给data中r行c位置 222 this.data[r][c]=this.data[r][nextc]; 223 //将data中r行nextc位置置为0 224 this.data[r][nextc]=0; 225 c--;//下次还在当前位置开始 226 }else if(this.data[r][c]==this.data[r][nextc]){ 227 //否则 如果data中r行c位置等于data中r行nextc位置 228 this.data[r][c]*=2;//将data中r行c位置*2 229 this.score+=this.data[r][c];//累加得分 230 //将data中r行nextc位置置为0 231 this.data[r][nextc]=0; 232 } 233 } 234 } 235 }, 236 //查找r行c列右侧下一个不为0的位置 237 getNextInRow:function(r,c){ 238 //nextc从c+1开始,到<CN结束,nextc每次增1 239 for(var nextc=c+1;nextc<this.CN;nextc++){ 240 //如果data中r行nextc位置的值!=0 241 if(this.data[r][nextc]!=0){ 242 return nextc;//返回nextc 243 } 244 }//(遍历结束)就返回-1 245 return -1; 246 }, 247 //将data中的元素,更新到页面的格子div中 248 updateView:function(){ 249 //r从0开始,到<RN结束,每次增1 250 for(var r=0;r<this.RN;r++){ 251 //c从0开始,到<CN结束,每次增1 252 for(var c=0;c<this.CN;c++){ 253 //查找id为c+r+c的div元素,保存在变量div中 254 var div=document.getElementById("c"+r+c); 255 //如果data中r行c列的等于0 256 if(this.data[r][c]==0){ 257 div.innerHTML="";//设置div的内容为空字符串 258 div.className="cell";//设置div的className为"cell" 259 }else{//否则 260 //设置div的内容为data中r行c列的值 261 div.innerHTML=this.data[r][c]; 262 //设置div的className为"cell n"+data中r行c列的值 263 div.className="cell n"+this.data[r][c]; 264 } 265 } 266 } 267 //找到id为score的span,直接设置其内容为score属性值 268 score.innerHTML=this.score; 269 //设置id为gameOver的元素的display属性为: 270 //如果state为GAMEOVER,就设置为"block",否则为"none" 271 this.state==this.GAMEOVER 272 &&(final.innerHTML=this.score); 273 gameOver.style.display= 274 this.state==this.GAMEOVER?"block":"none"; 275 }, 276 randomNum:function(){//在随机位置生成一个数字 277 while(true){//反复生成数字(死循环) 278 //在0~RN-1之间生成一个随机的行号,保存在r中 279 var r=Math.floor(Math.random()*this.RN); 280 //在0~CN-1之间生成一个随机的列号,保存在c中 281 var c=Math.floor(Math.random()*this.CN); 282 if(this.data[r][c]==0){//如果data中r行c列为0 283 //随机生成一个数字保存在变量num中 284 var num=Math.random(); 285 //设置data中r行c列的元素值为: 286 //如果num<0.5,就设置2为,否则就设置为4 287 this.data[r][c]=num<0.5?2:4; 288 break;//退出循环 289 } 290 } 291 }, 292 } 293 //当页面加载后,自动启动 294 window.onload=function(){game.start();}