js贪吃蛇(构造函数)

 

给大家分享一下这几天我研究的一个贪吃蛇,挺简单的,但是实现起来其实有点绕的,我给大家附上完整代码,一起分析学习一下,主要用的是构造函数。

   

  

 

 

思想:

1、设计蛇:属性有宽、高、方向、状态(有多少节),方法:显示,跑

2、设计食物:属性宽、高

3、显示蛇:根据状态向地图里加元素

4、蛇跑起来:下一节到前一节的位置,蛇头根据方向变,删除原来的蛇,新建蛇;当出界时,死亡,初始化;当蛇头吃到自己的时候,死亡,初始化

5、食物被吃掉,蛇加一节,去掉原来的食物,生成新的食物

6、添加定时器,绑定按键

 

这里先给大家简单的说一下构造函数:

构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载

 

new data();

 

然后开始我们的贪吃蛇之旅:

1.设置变量,定义蛇的初始状态

 1  // 设置蛇的宽、高、默认走的方向
 2             this.width = 10;
 3             this.height = 10;
 4             this.direction = 'right';
 5 
 6             // 记住蛇的状态,当吃完食物的时候,就要加一个,初始为3个小点为一个蛇,
 7             this.body = [
 8                 {x:2, y:0},   // 蛇头,第一个点
 9                 {x:1, y:0},   // 蛇脖子,第二个点
10                 {x:0, y:0},   // 蛇尾,第三个点
11             ];

这里面我会在代码里做详细的解释,大家注意看!!!!

2.显示蛇

 1  for (var i=0; i<this.body.length; i++) {
 2                     if (this.body[i].x != null) {   // 当吃到食物时,x==null,不能新建,不然会在0,0处新建一个
 3                         var s = document.createElement('div');//创建元素节点
 4                         // 将节点保存到状态中,以便于后面删除
 5                         this.body[i].flag = s;
 6                         // 设置宽高
 7                         s.style.width = this.width + 'px';
 8                         s.style.height = this.height + 'px';
 9                         s.style.borderRadius =  "50%";
10                         s.style.background = "rgb(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + ")";//这个就是一个随机颜色
11                         // 设置位置
12                         s.style.position = 'absolute';
13                         s.style.left = this.body[i].x * this.width + 'px';
14                         s.style.top = this.body[i].y * this.height + 'px';//设置每一个舍身的位置  
15                         // 添加进去
16                         map.appendChild(s);//把元素追加到div中
17                     }
18                 }

这里使用到for循环,为每一个对象创建一个flag对象,也就是蛇身。

3.让蛇动起来

我的想法就是让后一个元素到前一个元素来,然后这样蛇就动起来了,

1 // 后一个元素到前一个元素的位置
2                 for (var i=this.body.length-1; i>0; i--) {
3                     this.body[i].x = this.body[i-1].x;
4                     this.body[i].y = this.body[i-1].y;
5                     //这里就相当于是后一个元素到前一个元素  这样让小蛇动起来
6                 }

4.调整蛇头方向

 1 // 根据方向处理蛇头
 2                 switch(this.direction)
 3                 {
 4                     //这里不仅调整蛇头方向,还为迟到的食物赋值  下边会有解释
 5                     case "left":
 6                         this.body[0].x -= 1;
 7                         break;
 8                     case "right":
 9                         this.body[0].x += 1;
10                         break;
11                     case "up":
12                         this.body[0].y -= 1;
13                         break;
14                     case "down":
15                         this.body[0].y += 1;
16                         break;
17                 }

5.判断吃到食物和吃到自己和撞墙的事件

这里提醒一下呢就是,不管你是吃到食物了还是撞墙了还是吃到自己了你到要重新创建蛇。

然后呢我会在代码里标注清楚每一个代码的作用。

 1  // 判断是否出界,一蛇头判断,出界的话,
 2                 if (this.body[0].x < 0 || this.body[0].x > 79 || this.body[0].y < 0 || this.body[0].y > 39) {
 3                     clearInterval(timer);   // 清除定时器,
 4                     alert("你瞎吗?撞死了!");
 5                     // 删除旧的
 6                     for (var i=0; i<this.body.length; i++) {
 7                         if (this.body[i].flag != null) {   // 如果刚吃完就死掉,会加一个值为null的
 8                             map.removeChild(this.body[i].flag);
 9                         }
10                     }
11                     //这里呢一定要删除 之后  初始化一下  因为上边的this.display() 为每一个body对象都添加了一个flag  所以这里删除原本的蛇 重新初始化一下蛇
12                     this.body = [   // 回到初始状态,
13                         {x:2, y:0},
14                         {x:1, y:0},
15                         {x:0, y:0}
16                     ];
17                     this.direction = 'right';
18                     this.display();   // 显示初始状态
19                     return false;   // 结束
20                 }
21                
22                 // 判断蛇头吃到食物,xy坐标重合,
23                 if (this.body[0].x == food.x && this.body[0].y == food.y) {
24                     // 蛇加一节,因为根据最后节点定,下面display时,会自动赋值的
25                     this.body.push({x:null, y:null, flag: null});
26 
27                     //在这里 看了上边的小伙伴可能会有疑惑  this.display  函数里面生成小蛇的判断是x!=null   那我吃到实物以后push进去的都是null  为什么还会创建出来????
28                     //这里呢大家就注意看  this.run()  这个方法  他让后一个元素到前一个元素来  然后你新添加的这一截蛇它会被替换为蛇头  然后进入 下边的switch语句  x,y都会变为-1 或者是1  那么这个时候在走上边的 this.display() 就可以生成一个新的小蛇。
29 
30 
31                     // 清除食物,重新生成食物
32                     map.removeChild(food.flag);
33                     food.display();
34                 }
35                 // 吃到自己死亡,从第五个开始与头判断,因为前四个永远撞不到
36                 for (var i=4; i<this.body.length; i++) {
37                     if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
38                         clearInterval(timer);   // 清除定时器,
39                         alert("傻子!你怎么能吃自己呢?");
40                         // 删除旧的
41                         for (var i=0; i<this.body.length; i++) {
42                             if (this.body[i].flag != null) {   // 如果刚吃完就死掉,会加一个值为null的
43                                 map.removeChild(this.body[i].flag);
44                             }
45                         }
46                         this.body = [   // 回到初始状态,
47                             {x:2, y:0},
48                             {x:1, y:0},
49                             {x:0, y:0}
50                         ];
51                         this.direction = 'right';
52                         this.display();   // 显示初始状态
53                         return false;   // 结束
54                     }
55                 }
56 
57                 // 先删掉初始的蛇,在显示新蛇
58                 for (var i=0; i<this.body.length; i++) {
59                     if (this.body[i].flag != null) {   // 当吃到食物时,flag是等于null,且不能删除
60                         map.removeChild(this.body[i].flag);
61                     }
62                 }
63                 // 重新显示蛇
64                 this.display();

 

6.构造食物

食物呢,我们就是创建一个,当蛇吃到食物,也就是蛇头与食物的xy坐标一样后删除食物,然后随机新建一个食物

 1   this.width = 10;
 2             this.height = 10;
 3 
 4             this.display = function() {
 5                 var f = document.createElement('div');
 6                 this.flag = f;
 7                 f.style.width = this.width + 'px';
 8                 f.style.height = this.height + 'px';
 9                 f.style.background = 'red';
10                 f.style.borderRadius = '50%';
11                 f.style.position = 'absolute';
12                 //设置随机位置
13                 this.x = Math.floor(Math.random()*80);
14                 this.y = Math.floor(Math.random()*40);
15                 f.style.left = this.x * this.width + 'px';
16                 f.style.top = this.y * this.height + 'px';
17                 //把创建好的食物添加进地图里
18                 map.appendChild(f);

 

7.然后我们要使用构造函数调用食物和蛇的方法

1 var snake = new Snake();// 构造函数
2         var food = new Food();
3         snake.display();   // 初始化显示
4         food.display();

这里呢,一定要注意,他改变了this的指向,大家可以输出一下this指向,

如果直接调用函数的话,this是指向window,使用构造函数的话this就指向调用者

8.点击开始游戏添加键盘事件

 1 document.body.onkeydown = function(e) {
 2             // 有事件对象就用事件对象,没有就自己创建一个,兼容低版本浏览器
 3             var ev = e || window.event;
 4 
 5             switch(ev.keyCode)
 6             {
 7                 case 38:
 8                     if (snake.direction != 'down') {   // 不允许返回,向上的时候不能向下
 9                         snake.direction = "up";
10                     }
11                     break;
12                 case 40:
13                     if (snake.direction != "up") {
14                         snake.direction = "down";
15                     }
16                     break;
17                 case 37:
18                     if (snake.direction != "right") {
19                         snake.direction = "left";
20                     }
21                     break;
22                 case 39:
23                     if (snake.direction != "left") {
24                         snake.direction = "right";
25                     }
26                     break;
27             }
28         };

9.设置定时器,让小蛇自己动起来

 

1 // 点击开始时,动起来
2         var begin = document.getElementById('begin');
3         var timer;
4         begin.onclick = function() {
5             clearInterval(timer);
6               // 先执行run函数,把执行得到的结果,每500毫秒执行一次,不会在执行内部代码
7              // 小技巧,每500毫秒执行字符串,字符串执行内部代码
8              timer = setInterval("snake.run()", 500);
9         };

最后一定要记住,调用定时器前一定要先清除定时器!!!!

 

给大家附上完整代码:

 

  1 <!doctype html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <meta name="viewport"
  6           content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  7     <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8     <title>Document</title>
  9     <style type="text/css">
 10         body {
 11             margin: 0;
 12             padding: 0;
 13         }
 14         .main {
 15             width: 800px;
 16             height: 400px;
 17             margin: 50px auto;
 18         }
 19         .btn {
 20             width: 100px;
 21             height: 40px;
 22             background: red;
 23         }
 24         .map {
 25             position: relative;
 26             width: 800px;
 27             height: 400px;
 28             background: yellow;
 29         }
 30     </style>
 31 </head>
 32 <body>
 33 <div class="main">
 34     <button class="btn" id="begin">开始游戏</button>
 35     <div class="map" id="map"></div>
 36 
 37     <script type="text/javascript">
 38         var map = document.getElementById('map');
 39         // 使用构造方法创建蛇,
 40         function Snake()
 41         {
 42             // 设置蛇的宽、高、默认走的方向
 43             this.width = 10;
 44             this.height = 10;
 45             this.direction = 'right';
 46 
 47             // 记住蛇的状态,当吃完食物的时候,就要加一个,初始为3个小点为一个蛇,
 48             this.body = [
 49                 {x:2, y:0},   // 蛇头,第一个点
 50                 {x:1, y:0},   // 蛇脖子,第二个点
 51                 {x:0, y:0},   // 蛇尾,第三个点
 52             ];
 53 
 54             // 显示蛇
 55             this.display = function() {
 56                 // 创建蛇
 57                 for (var i=0; i<this.body.length; i++) {
 58                     if (this.body[i].x != null) {   // 当吃到食物时,x==null,不能新建,不然会在0,0处新建一个
 59                         var s = document.createElement('div');//创建元素节点
 60                         // 将节点保存到状态中,以便于后面删除
 61                         this.body[i].flag = s;
 62                         // 设置宽高
 63                         s.style.width = this.width + 'px';
 64                         s.style.height = this.height + 'px';
 65                         s.style.borderRadius =  "50%";
 66                         s.style.background = "rgb(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + ")";//这个就是一个随机颜色
 67                         // 设置位置
 68                         s.style.position = 'absolute';
 69                         s.style.left = this.body[i].x * this.width + 'px';
 70                         s.style.top = this.body[i].y * this.height + 'px';//设置每一个舍身的位置  
 71                         // 添加进去
 72                         map.appendChild(s);//把元素追加到div中
 73                     }
 74                 }
 75             };
 76 
 77             // 让蛇跑起来,后一个元素到前一个元素的位置
 78             // 蛇头根据方向处理,所以i不能等于0
 79             this.run = function() {
 80                 // 后一个元素到前一个元素的位置
 81                 for (var i=this.body.length-1; i>0; i--) {
 82                     this.body[i].x = this.body[i-1].x;
 83                     this.body[i].y = this.body[i-1].y;
 84                     //这里就相当于是后一个元素到前一个元素  这样让小蛇动起来
 85                 }
 86 
 87                 // 根据方向处理蛇头
 88                 switch(this.direction)
 89                 {
 90                     //这里不仅调整蛇头方向,还为迟到的食物赋值  下边会有解释
 91                     case "left":
 92                         this.body[0].x -= 1;
 93                         break;
 94                     case "right":
 95                         this.body[0].x += 1;
 96                         break;
 97                     case "up":
 98                         this.body[0].y -= 1;
 99                         break;
100                     case "down":
101                         this.body[0].y += 1;
102                         break;
103                 }
104 
105                 // 判断是否出界,一蛇头判断,出界的话,
106                 if (this.body[0].x < 0 || this.body[0].x > 79 || this.body[0].y < 0 || this.body[0].y > 39) {
107                     clearInterval(timer);   // 清除定时器,
108                     alert("你瞎吗?撞死了!");
109                     // 删除旧的
110                     for (var i=0; i<this.body.length; i++) {
111                         if (this.body[i].flag != null) {   // 如果刚吃完就死掉,会加一个值为null的
112                             map.removeChild(this.body[i].flag);
113                         }
114                     }
115                     //这里呢一定要删除 之后  初始化一下  因为上边的this.display() 为每一个body对象都添加了一个flag  所以这里删除原本的蛇 重新初始化一下蛇
116                     this.body = [   // 回到初始状态,
117                         {x:2, y:0},
118                         {x:1, y:0},
119                         {x:0, y:0}
120                     ];
121                     this.direction = 'right';
122                     this.display();   // 显示初始状态
123                     return false;   // 结束
124                 }
125                
126                 // 判断蛇头吃到食物,xy坐标重合,
127                 if (this.body[0].x == food.x && this.body[0].y == food.y) {
128                     // 蛇加一节,因为根据最后节点定,下面display时,会自动赋值的
129                     this.body.push({x:null, y:null, flag: null});
130 
131                     //在这里 看了上边的小伙伴可能会有疑惑  this.display  函数里面生成小蛇的判断是x!=null   那我吃到实物以后push进去的都是null  为什么还会创建出来????
132                     //这里呢大家就注意看  this.run()  这个方法  他让后一个元素到前一个元素来  然后你新添加的这一截蛇它会被替换为蛇头  然后进入 下边的switch语句  x,y都会变为-1 或者是1  那么这个时候在走上边的 this.display() 就可以生成一个新的小蛇。
133 
134 
135                     // 清除食物,重新生成食物
136                     map.removeChild(food.flag);
137                     food.display();
138                 }
139                 // 吃到自己死亡,从第五个开始与头判断,因为前四个永远撞不到
140                 for (var i=4; i<this.body.length; i++) {
141                     if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
142                         clearInterval(timer);   // 清除定时器,
143                         alert("傻子!你怎么能吃自己呢?");
144                         // 删除旧的
145                         for (var i=0; i<this.body.length; i++) {
146                             if (this.body[i].flag != null) {   // 如果刚吃完就死掉,会加一个值为null的
147                                 map.removeChild(this.body[i].flag);
148                             }
149                         }
150                         this.body = [   // 回到初始状态,
151                             {x:2, y:0},
152                             {x:1, y:0},
153                             {x:0, y:0}
154                         ];
155                         this.direction = 'right';
156                         this.display();   // 显示初始状态
157                         return false;   // 结束
158                     }
159                 }
160 
161                 // 先删掉初始的蛇,在显示新蛇
162                 for (var i=0; i<this.body.length; i++) {
163                     if (this.body[i].flag != null) {   // 当吃到食物时,flag是等于null,且不能删除
164                         map.removeChild(this.body[i].flag);
165                     }
166                 }
167                 // 重新显示蛇
168                 this.display();
169 
170             }
171         }
172 
173         // 构造食物
174         function Food()
175         {
176             this.width = 10;
177             this.height = 10;
178 
179             this.display = function() {
180                 var f = document.createElement('div');
181                 this.flag = f;
182                 f.style.width = this.width + 'px';
183                 f.style.height = this.height + 'px';
184                 f.style.background = 'red';
185                 f.style.borderRadius = '50%';
186                 f.style.position = 'absolute';
187                 //设置随机位置
188                 this.x = Math.floor(Math.random()*80);
189                 this.y = Math.floor(Math.random()*40);
190                 f.style.left = this.x * this.width + 'px';
191                 f.style.top = this.y * this.height + 'px';
192                 //把创建好的食物添加进地图里
193                 map.appendChild(f);
194             }
195         }
196 
197         var snake = new Snake();// 构造函数
198         var food = new Food();
199         snake.display();   // 初始化显示
200         food.display();
201 
202         // 给body加按键事件,上下左右
203         document.body.onkeydown = function(e) {
204             // 有事件对象就用事件对象,没有就自己创建一个,兼容低版本浏览器
205             var ev = e || window.event;
206 
207             switch(ev.keyCode)
208             {
209                 case 38:
210                     if (snake.direction != 'down') {   // 不允许返回,向上的时候不能向下
211                         snake.direction = "up";
212                     }
213                     break;
214                 case 40:
215                     if (snake.direction != "up") {
216                         snake.direction = "down";
217                     }
218                     break;
219                 case 37:
220                     if (snake.direction != "right") {
221                         snake.direction = "left";
222                     }
223                     break;
224                 case 39:
225                     if (snake.direction != "left") {
226                         snake.direction = "right";
227                     }
228                     break;
229             }
230         };
231 
232         // 点击开始时,动起来
233         var begin = document.getElementById('begin');
234         var timer;
235         begin.onclick = function() {
236             clearInterval(timer);
237               // 先执行run函数,把执行得到的结果,每500毫秒执行一次,不会在执行内部代码
238              // 小技巧,每500毫秒执行字符串,字符串执行内部代码
239              timer = setInterval("snake.run()", 500);
240         };
241 
242 
243     </script>
244 </div>
245 </body>
246 </html>

 

 

 

详细的解释我已经在代码中注释,大家把代码复制下来就可以直接查看效果!!!

 

 

posted @ 2019-12-06 10:15  蔡徐坤学前端  阅读(492)  评论(0编辑  收藏  举报