【我的js练习】游戏篇 - --- 贪吃蛇

一、主要思路

    1、游戏地图创建:使用table生成地图,地图大小可调;

  2、蛇和食物的随机生成:蛇使用对象数组来维护蛇的身体,食物采用随机生成的{"x":x,"y":y}。

  3、蛇行动和控制相关:keydown事件添加;

    4、失败条件判断:撞墙失败和咬自己失败;

二、重点

   1、地图、蛇、食物的一格对应的是{"x":x,"y":y}的对象。这样子就可以通过坐标的加减判断蛇的移动;

   2、蛇、食物的移动“渲染”,暂且叫“渲染”,这个说法很不规范。比如30*30格的地图,对应的每个对象“0,0”、“0,1”……“0,29”其实就是一格30进制的数,而且只有两位,这样不必使用循环就可以“渲染”出蛇和食        物;

三、效果

【我的js练习】游戏篇 - --- 贪吃蛇_第1张图片

四、代码

   

  1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2 <html xmlns="http://www.w3.org/1999/xhtml">
  3 <head>
  4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5 <title> 贪吃蛇(面向对象版)</title>
  6 <style type="text/css">
  7 html,body{overflow:hidden;}
  8 body,div,p{margin:0;padding:0;}
  9 body{background:#000;font:12px/1.5 arial;color:#7A7A7A;}
 10 a{text-decoration:none;outline:none;}
 11 #tips,#copyright{position:absolute;width:100%;height:50px;text-align:center;background:#171717;border:2px solid #484848;}
 12 #tips{top:0;border-width:0 0 2px;}
 13 #tips a{font:14px/30px arial;color:#FFF;background:#F06;display:inline-block;margin:10px 5px 0;padding:0 15px;border-radius:15px;}
 14 #tips a.active{background:#FE0000;}
 15 #copyright{bottom:0;line-height:50px;border-width:2px 0 0;}
 16 #copyright a{color:#FFF;background:#7A7A7A;padding:2px 5px;border-radius:10px;}
 17 #copyright a:hover{background:#F90;}
 18 #box{background:#eee;width: 100%;height: 720px;margin: 50px 0px;}
 19 p{position:absolute;top:55px;width:100%;text-align:center;}
 20 #box #panle{width: 100%;height: 93%;padding-top: 30px;}
 21 #panle table{border-collapse: collapse; margin: 0 auto;}
 22 #panle table td{
 23 border: 1px solid #808080; 
 24 width: 10px; 
 25 height: 10px; 
 26 font-size: 0; 
 27 line-height: 0; 
 28 overflow: hidden; }
 29 .food{background: green;}
 30 .snake{background: #555;}
 31 </style>
 32 <script type="text/javascript">
 33 var fgm = {
 34   on: function(element, type, handler) {
 35     return element.addEventListener ? element.addEventListener(type, handler, false) : element.attachEvent("on" + type, handler)
 36   },
 37   un: function(element, type, handler) {
 38     return element.removeEventListener ? element.removeEventListener(type, handler, false) : element.detachEvent("on" + type, handler)
 39   },
 40   bind: function(object, handler) {
 41     return function() {
 42       return handler.apply(object, arguments) 
 43     } 
 44   },
 45   randomRange: function(lower, upper) {
 46     return Math.floor(Math.random() * (upper - lower + 1) + lower)  
 47   },
 48   getRanColor: function() {
 49     var str = this.randomRange(0, 0xFFFFFF).toString(16);
 50     while(str.length < 6) str = "0" + str;
 51     return "#" + str  
 52   },
 53   has:function(a,arry){
 54    var flag = false;
 55    for(var i = 0; i < arry.length; i++){
 56       if(fgm.equal(a,arry[i])){
 57         flag  = true;
 58       }
 59    }
 60    return flag;
 61   },
 62   equal:function(a,b)
 63   {
 64     return a.x == b.x && a.y == b.y;
 65   },
 66   cast:function(m,n)
 67   {
 68     // m进制 n 待转换参数
 69     if(typeof(n) === "object"){
 70       // 转换成10进制
 71       return n.x * m + n.y;
 72     }else{
 73       // 转换成m进制
 74       var y = n % m;
 75       var x = (n/m) % m;
 76       return {"x":x,"y":y} 
 77     }
 78   }
 79 };
 80 //初始化对象
 81 function Snake() {
 82     this.map = 30;    // 地图大小
 83     this.speed = 500;   // 速度
 84   this.fnInit = fgm.bind(this, this.initialize)
 85 }
 86 Snake.prototype = {
 87   initialize:function(obj)
 88   { 
 89     this.oParent = obj;
 90     this.space = [];
 91     this.type = 0;  //0暂停 1开始 2失败
 92     this.timer = null;
 93     this.score = 0;   // 速度
 94     this.direction = 3; // 0 1 2 3 - 上 下 左 右 默认开始向右跑
 95     this.snake = [{"x":0,"y":0}];  // 蛇身体
 96     this.food = null; // 食物
 97     this.__create__();
 98   },
 99   __create__:function()
100   {
101     var oThis = this;
102     this.tab = this.oParent.getElementsByTagName("table")[0];
103     this.tab && (this.oParent.removeChild(this.tab));
104     this.tab = document.createElement("table");
105     var oFrag = document.createDocumentFragment();
106     var i = 0;
107     for(i = 0; i < this.map; i++)
108     {
109       var oTr = document.createElement("tr");
110       for(var j = 0; j < oThis.map; j++)
111       {
112         var oTd = document.createElement("td");
113         oTr.appendChild(oTd);
114         this.space.push({"x":i,"y":j,"obj":oTd});
115       }
116       oFrag.appendChild(oTr);
117     }
118     this.tab.appendChild(oFrag);
119     this.oParent.appendChild(this.tab);
120     this.td = this.tab.getElementsByTagName("td");
121     this.food = this.randomFood();
122     this.changeSnake();
123     this.changeFood();
124   },
125   start:function()
126   { 
127     var oThis = this;
128     fgm.on(document,"keydown",function(event){
129       var e = event || window.event;
130       switch(e.keyCode)
131       {
132         case 37: // left 2 
133           if(oThis.direction == 0 || oThis.direction == 1){
134             oThis.direction = 2;
135           } 
136         break;
137         case 38: // up 0 
138           if(oThis.direction == 2 || oThis.direction == 3){
139             oThis.direction = 0;
140           } 
141         break;
142         case 39: // right 3
143           if(oThis.direction == 0 || oThis.direction == 1){
144             oThis.direction = 3;
145           } 
146         break;
147         case 40: // down 1
148           if(oThis.direction == 2 || oThis.direction == 3){
149             oThis.direction = 1;
150           } 
151         break;
152       }
153       //console.log(oThis.direction)
154     });
155     oThis.doMove(this.speed);
156   },
157   doMove:function(ispeed,fn)
158   {
159     clearInterval(this.timer);
160     var oThis = this;
161     this.timer = setInterval(function(){
162       var next = oThis.nextFn();
163       if(fgm.equal(next,oThis.food)){
164         oThis.snake.unshift(oThis.food);
165         oThis.food = oThis.randomFood();
166         oThis.changeFood();
167         oThis.changeSnake();
168         next = oThis.nextFn();
169         oThis.score++;
170       }
171       oThis.faild(next) && (clearInterval(oThis.timer),alert("GAME OVER YOUR SCORE IS "+oThis.score));
172       oThis.snake.unshift(next);
173       oThis.snake.pop();
174       oThis.changeSnake();
175     },oThis.speed)
176   },
177   faild:function(a)
178   {
179     var wall = false;
180     var bite = false;
181     switch(this.direction)
182     {
183       case 3:
184         a.y >= this.map && (wall = true);
185       break;
186       case 1:
187         a.x >= this.map && (wall = true);
188       break;
189       case 2:
190         a.y < 0 && (wall = true);
191       break;
192       case 0:
193         a.x < 0 && (wall = true);
194       break;
195     } 
196     bite = fgm.has(a,this.snake);
197     return wall || bite;
198   },
199   nextFn:function()
200   { 
201     var x,y = 0;
202     var oThis = this;
203     this.direction == 3 &&( x = this.snake[0].x ,y = this.snake[0].y + 1);
204     this.direction == 1 &&( x = this.snake[0].x + 1 ,y = this.snake[0].y);
205     this.direction == 2 &&( x = this.snake[0].x ,y = this.snake[0].y - 1);
206     this.direction == 0 &&( x = this.snake[0].x - 1 ,y = this.snake[0].y);
207     var a = {"x":x,"y":y};
208     return a;
209   },
210   randomFood:function()
211   {
212     var a = {"x":fgm.randomRange(1,this.map-1),"y":fgm.randomRange(1,this.map-1)};
213     if(fgm.has(a,this.snake)){
214       this.food();
215     }else{
216       return a;
217     }
218   },
219   changeSnake:function()
220   { 
221     var oThis = this;
222     for(var i = 0; i < this.space.length; i++)this.space[i].obj.className = "";
223     for(var i = 0; i < this.snake.length; i++){
224      this.space[fgm.cast(oThis.map,oThis.snake[i])].obj.className = "snake";
225     }
226     this.changeFood();
227   },
228   changeFood:function()
229   {
230     this.space[fgm.cast(this.map,this.food)].obj.className = "food";
231   },
232   stop:function()
233   {
234     this.timer && clearInterval(this.timer);
235   }
236 };
237 
238 fgm.on(window, "load", function() {
239   var oTips = document.getElementById("tips");
240   var aBtn = oTips.getElementsByTagName("a");
241   var select = oTips.getElementsByTagName("select");
242   var panle = document.getElementById("panle");
243   var snake = new Snake();
244   fgm.on(oTips, "click", function(event) {
245     var oEvent = event || window.event;
246     var oTarget = oEvent.target || oEvent.srcElement;
247     var i = 0;
248     if(oTarget.tagName.toUpperCase() == "A") {
249       for(i = 0; i < aBtn.length; i++) aBtn[i].className = "";
250       switch(oTarget.id) {
251         case "start":
252           snake.type = 1;
253           snake.start();
254           for(var j = 0; j < select.length; j++){
255             select[j].disabled = true;
256           }
257           break;
258         case "stop":
259           snake.type = 0;
260           snake.stop();
261           break;
262       }
263       oTarget.className = "active";         
264       oEvent.stopPropagation ? oEvent.stopPropagation() : oEvent.cancelBubble = true
265     }
266   });
267   fgm.on(select[0],"change",function(){
268     snake.map = select[0].value;
269     snake.initialize(panle);
270   });
271   fgm.on(select[1],"change",function(){
272     snake.speed = select[1].value;
273     snake.initialize(panle);
274   });
275   snake.initialize(panle);
276 });
277 fgm.on(document, "contextmenu", function(event) {
278   var oEvent = event || window.event;
279   oEvent.preventDefault ? oEvent.preventDefault() : oEvent.returnValue = false
280 });
281 </script>
282 </head>
283 <body>
284 <div id="tips"><a id="start" href="javascript:;">开始游戏</a><a id="stop" href="javascript:;">停止游戏</a>
285   <select id="map">
286     <option value = "30">30 * 30</option>
287     <option value = "40">40 * 40</option>
288     <option value = "50">50 * 50</option>
289   </select>
290   <select id="speed">
291     <option value = "500">速度 - 慢</option>
292     <option value = "300">速度 - 中</option>
293     <option value = "200">速度 - 快</option>
294   </select>
295   <p>游戏使用键盘“上下左右”控制,点击开始游戏开始</p>
296 </div>
297 
298 <div id="box">
299 
300 <div id="panle">
301 </div>
302 </div>
303 <div id="copyright">建议使用Firefox, Chrome浏览器预览效果. 如蒙转载请注明出处 <a href="http://weibo.com/3839963356/profile?topnav=1&wvr=6&is_all=1">winter</a> , By — ben, QQ:1583145833</div>
304 </body>
305 </html>

 

你可能感兴趣的:(【我的js练习】游戏篇 - --- 贪吃蛇)