给大家分享一下这几天我研究的一个贪吃蛇,挺简单的,但是实现起来其实有点绕的,我给大家附上完整代码,一起分析学习一下,主要用的是构造函数。
思想:
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>
详细的解释我已经在代码中注释,大家把代码复制下来就可以直接查看效果!!!