贪吃蛇案例主要分为四个部分:

  1 > 地图

  2 > 食物

     主要是设置随机的食物,还有食物的范围

  3 > 小蛇

     在设置小蛇运动的时,需要内部的每个盒子都进行移动,移动是通过坐标的修改来实现的,除了蛇头以外,其余的蛇身中的每一个部分都可以使用上一个蛇身的坐标值.  但是,使用正向遍历的时候,导致所有的蛇身坐标都是蛇头的坐标,这个时候,我采用了反向遍历的方式

     后期需要给蛇头的坐标进行单独的设置

  4 > 游戏控制

    1.设置食物和小蛇的显示

    2.设置小蛇的自动运动

      使用定时器,让小蛇进行自身的移动

      检测小蛇是否迟到食物–使用蛇头的坐标和食物的坐标进行对比

      检测游戏是否结束

        小蛇撞墙(坐标范围X=0-39;Y=0-29;)==>结束

        小蛇撞到自己(从第五个坐标进行检测)==>结束

    3.设置用户的键盘操作–使用了e.keyCode属性值修改了小蛇中的运动属性

 

<!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4   <meta charset="UTF-8">
  5   <title>今天天气不错</title>
  6   <style>
  7     * {
  8       margin: 0;
  9       padding: 0;
 10     }
 11     
 12     #map {
 13       width: 800px;
 14       height: 600px;
 15       background-color: #CCCCCC;
 16       position: relative;
 17     }
 18     
 19     #map div {
 20       /*用于设置地图中的食物,小蛇的盒子定位*/
 21       position: absolute;
 22     }
 23     #button{
 24       float: right;
 25       height: 50px;
 26       line-height: 50px;
 27     }
 33   </style>
 34 </head>
 35 <body>
 36 
 37 <div id="map"></div>
 38 <div id="button">
 41 </div>
 42 
 43 <script>
 44   //贪食蛇案例中一共分为4个部分(对象)
 45   //1 地图  2 食物 3 小蛇 4 游戏控制
 46 
 47   //食物对象
 48   (function () {
 49     
 50     function Food(options) {
 51       //每个食物所必须的属性
 52       //宽 高 背景色 坐标 放置位置
 53       this.width = options.width || 20;
 54       this.height = options.height || 20;
 55       this.bgColor = options.bgColor || "green";
 56       
 57       //坐标设置:只是为了在后期维护时,查看属性比較方便
 58       this.x = 0;
 59       this.y = 0;
 60       
 61       //放置位置
 62       this.map = options.map;
 63       
 64       //用于保存当前存在的食物盒子的DOM对象
 65       this.element = null;
 66     }
 67     
 68     //对食物进行初始化操作(设置盒子的显示效果)
 69     Food.prototype.init = function () {
 70       //删除旧的食物盒子
 71       if (this.element) {
 72         this.map.removeChild(this.element);
 73       }
 74       
 75       //1 创建食物盒子
 76       var div = document.createElement("div");
 77       //---为了在删除盒子时可以找到当前创建的盒子,先进行一次保存,保存在实例对象的属性中
 78       this.element = div;
 79       
 80       //2 设置样式
 81       div.style.width = this.width + "px";
 82       div.style.height = this.height + "px";
 83       div.style.backgroundColor = this.bgColor;
 84       //3 放入到地图中
 85       this.map.appendChild(div);
 86       
 87       //4 调用this的随机位置方法
 88       this.setRandomPos();
 89     };
 90     
 91     //设置食物盒子的随机位置
 92     Food.prototype.setRandomPos = function () {
 93       //先计算出随机的坐标值,再根据坐标值设置对应的left/top即可
 94       //1 先计算可以容纳的坐标最大值
 95       //this.map.offsetWidth / this.width
 96       //2 获取范围内的随机坐标
 97       this.x = Math.floor(Math.random() * this.map.offsetWidth / this.width);
 98       this.y = Math.floor(Math.random() * this.map.offsetHeight / this.height);
 99       
100       //3 根据坐标设置left和top属性
101       this.element.style.left = this.x * this.width + "px";
102       this.element.style.top = this.y * this.height + "px";
103     };
104     
105     //暴露操作
106     window.Food = Food;
107   })();
108   
109   //小蛇对象
110   (function () {
111     
112     function Snake(options) {
113       //分析小蛇对象需要哪些属性?
114       //宽 高 背景色 坐标 放置位置 运动方向
115       
116       //将宽高设置为统一的值,其他的坐标等属性进行分别设置
117       this.width = options.width || 20;
118       this.height = options.height || 20;
119       
120       //设置坐标:采用一种较为复杂的结构,目的是保存蛇身内每个小盒子的坐标值
121       this.body = [
122         //当前设置的为小蛇初始的坐标与颜色
123         {x: 3, y: 1, color: "red"},//蛇头
124         {x: 2, y: 1, color: "pink"},//蛇身
125         {x: 1, y: 1, color: "pink"},//蛇身
126       ];
127       //设置放置位置
128       this.map = options.map;
129       //设置运动方向
130       this.direction = options.direction || "right";
131       
132       //设置一个属性,用于保存蛇身的所有结构(DOM对象),目的为删除时可以找到对应的元素
133       this.elements = [];
134     }
135     
136     //设置小蛇的显示的方法:
137     Snake.prototype.init = function () {
138       //当我们要进行绘制之前,先将旧的蛇身结构进行删除
139       //要删除的是每个标签的结构,先进行遍历操作
140       
141       //可以提前对this.elements进行内容检测,但是没有必要
142 //      if(this.elements.length !== 0){}
143       for (var i = 0; i < this.elements.length; i++) {
144         //要删除的是每个标签的结构
145         this.map.removeChild(this.elements[i]);
146         //还需要进行数据的删除
147       }
148       this.elements = [];
149       
150       
151       //1 创建小蛇中的每个部分(遍历this.body中的所有对象)
152       //--- 每次创建完毕后,将蛇身保存到this.elements数组中
153       var div, body;
154       for (i = 0; i < this.body.length; i++) {
155         div = document.createElement("div");
156         div.style.width = this.width + "px";
157         div.style.height = this.height + "px";
158         
159         body = this.body[i];
160         div.style.backgroundColor = body.color;
161         //设置left top
162         div.style.left = body.x * this.width + "px";
163         div.style.top = body.y * this.height + "px";
164         this.map.appendChild(div);
165         this.elements.push(div);
166       }
167 //      console.log(this.elements);
168     };
169     
170     //设置小蛇运动的方法:
171     Snake.prototype.move = function () {
172       //分析:
173       //小蛇移动时,需要内部的每个盒子都进行移动,移动是通过坐标的修改实现
174       //除蛇头以外,其余的蛇身中的每个部分都可以使用上一个蛇身的坐标值
175       //蛇头根据运动方向进行判断判断设置即可
176       var body;//用于保存蛇身中的某个对象
177       
178     
179       //需要使用反向遍历的方式
180       for (var i = this.body.length - 1; i >= 1; i--) {
181         //body表示蛇身中的某一个盒子的所有坐标
182         body = this.body[i];
183         //获取前一项的坐标值即可
184         body.x = this.body[i - 1].x;
185         body.y = this.body[i - 1].y;
186       }
187       
188       
189       //给蛇头的坐标进行单独设置
190       //---后期添加的功能,根据当前操作的按键,设置不同的运动方向
191       //判断this.direction的值
192       switch (this.direction) {
193         case "left":
194           this.body[0].x--;
195           break;
196         case "right":
197           this.body[0].x++;
198           break;
199         case "up":
200           this.body[0].y--;
201           break;
202         case "down":
203           this.body[0].y++;
204           break;
205       }
206       
207       //小蛇body中的所有坐标值更新后,需要进行重新的绘制操作
208       //this.init();
209     };
210     
211     //暴露操作
212     window.Snake = Snake;
213   })();
214   
215   //游戏对象:用于操作food和snake进行结合,实现具体的游戏效果,规定了游戏的结束条件。。
216   (function () {
217     //游戏对象的设置:
218     //1 设置game对象的基本属性:snake food map
219     //2 设置game的初始化操作:
220     //   2.1 设置食物和小蛇显示
221     //   2.2 设置小蛇的自动运动
222     //   2.3 设置用户的键盘操作:设置keydown事件,并根据e.keyCode属性值修改snake的direction属性。
223     //3 在snake对象中修改move方法:根据2.3中修改的direction属性设置蛇头的坐标的更改方式。
224     
225     var that;//在游戏的自调用函数中声明一个变量,在game功能中均可访问
226     function Game(options) {
227       //需要的属性:  小蛇   食物   地图
228       this.snake = options.snake;
229       this.food = options.food;
230       this.map = options.map;
231       that = this;//保存当前实例对象,方便访问
232       
233     }
234     
235     //游戏初始化操作:
236     Game.prototype.init = function () {
237       //初始化食物
238       this.food.init();
239       //初始化小蛇
240       this.snake.init();
241       //设置小蛇跑动:让小蛇可以自动的进行move操作
242       this.snakeRun();
243       //设置键盘操作(改变小蛇的移动方向)
244       this.changeDirection();
245     };
246     
247     //设置小蛇的跑动方法:
248     Game.prototype.snakeRun = function () {
249       //设置一个定时器,间隔一段时间,让小蛇执行自身的move方法即可
250       var timer = null;
251       timer = setInterval(function () {
252         var snake = that.snake;//保存了snake对象
253         var food = that.food;//保存了food对象
254         var sheBody = snake.body;//保存了snake的body属性
255         
256         //获取移动之前蛇尾的横纵坐标
257         var lastX = sheBody[sheBody.length - 1].x;
258         var lastY = sheBody[sheBody.length - 1].y;
259         
260         //设置小蛇的运动
261         snake.move();
262 
263         //检测小蛇是否吃到了食物
264         //使用蛇头的坐标,和食物的坐标进行对比,如果x和y均相等。说明吃到了食物,添加一个新的蛇身
265         if (sheBody[0].x === food.x && sheBody[0].y === food.y) {
266           //获取之前蛇尾(蛇身中的最后一个盒子)的坐标,设置为新的对象,放入到蛇的body属性中
267           sheBody.push({x: lastX, y: lastY, color: "orange"});
268           //创建一个新的食物
269           food.init();
270         }
271         
272         
273         //检测游戏是否结束
274         //1 如果小蛇撞墙了,游戏结束
275         //蛇头的横坐标范围为  0-39
276         //蛇头的纵坐标范围为  0-29
277         var maxX = that.map.offsetWidth / food.width - 1;
278         var maxY = that.map.offsetHeight / food.height - 1;
279         
280         if (sheBody[0].x < 0 || sheBody[0].x > maxX || sheBody[0].y < 0 || sheBody[0].y > maxY) {
281           //清除定时器
282           clearInterval(timer);
283           alert("游戏结束");
284           //检测时,运动已经执行完毕了,渲染小蛇的操作init也执行完毕了,所以死后,蛇会出到地图之外
285           return;
286         }
287         
288         
289         //2 如果小蛇撞到了自己,游戏结束
290         //前四个(含蛇头)都不可能被蛇头撞到,所以从第五个蛇身开始检测。i表示索引值,从4开始检测。
291         for (var i = 4; i < sheBody.length; i++) {
292           if (sheBody[0].x == sheBody[i].x && sheBody[0].y == sheBody[i].y) {
293             alert("吃到自己了,游戏结束");
294             clearInterval(timer);
295             return;
296           }
297         }
298         
299         //在游戏结束后,不会画出移动到地图外的小蛇,也不会画出吃到自己的小蛇
300         snake.init();
301         
302         
303       }, 150);
304       
305     };
306     
307     //设置键盘操作:
308     Game.prototype.changeDirection = function () {
309       //给键盘设置操作:使用onkeydown事件,操作后的反应更自然
310       document.onkeydown = function (e) {
311         var e = e || window.event;
312         
313         //在点击按键时,返回某个按键的键盘码
314         //我们需要的按键为:  37左 38上 39右 40下
315         //console.log(e.keyCode);
316         that.keyCode = e.keyCode;
317         
318         //获取小蛇当前的运动方向
319         
320         var snakeDirc = that.snake.direction;
321         //根据点击后得到的键盘码,设置小蛇的不同运动方向
322         switch (true) {
323           case e.keyCode == 37 && snakeDirc != "right" :
324             that.snake.direction = "left";
325             break;
326           case e.keyCode == 38 && snakeDirc != "down" :
327             that.snake.direction = "up";
328             break;
329           case e.keyCode == 39 && snakeDirc != "left" :
330             that.snake.direction = "right";
331             break;
332           case e.keyCode == 40 && snakeDirc != "up" :
333             that.snake.direction = "down";
334             break;
335         }
336       };
337     };
338     //将game构造函数暴露给全局作用域
339     window.Game = Game;
340   })();
341   
342   
343   var map = document.getElementById("map");
344   var game = new Game({
345     map: map,
346     //传入时需要考虑game功能的需求,需要操作的是实例对象的属性和方法,所以传入的也是实例对象
347     snake: new Snake({map: map}),
348     food: new Food({map: map})
349   });
350   
351   //    console.log(g1);
352   //游戏开始:
353   game.init();
354 
355 
356 </script>
357 
358 </body>
359 </html>

 

版权声明:本文为AmorR原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/AmorR/articles/7944679.html