首页 > 代码库 > JavaScript实现简单贪吃蛇小游戏

JavaScript实现简单贪吃蛇小游戏

  之前上Web课,学到JavaScript的时候,老师要求写几个静态页面,要用到JavaScript。想了想就写个贪吃蛇吧。其实之前用pygame写过一次GUI的贪吃蛇,素材都是自己拿画图画的,其丑无比。所以这次还是老老实实用字符吧。

 

  首先,是一些全局变量的定义:

技术分享
 1 <script>
 2         var state = 0;//0 wait 1 run 2 over
 3     var width = 40;
 4     var height = 25;
 5     var update = false;
 6     var dir = 3; 
 7     var ndir = 3;
 8     //0 top 1 down 2 left 3 right
 9     //l 37 r 39 u 38 d 40  space 32
10 
11     var waittime = 50;
12 
13     //△▽○◇□☆●◆■★?◎¤?卍卐
14     var snakebody="■";//
15     var food = "★";//
16     var foodX;
17     var foodY;
18     var space = "□";
19     var snakeX;
20     var snakeY;
21     var length;
22 
23     var map;
24 
25     var drawMap;
26 
27     function debugInfo(str)
28     {
29         //document.getElementById("debug").innerHTML=str;
30         console.log(str);
31     }    
32 
33 ...
34 </script>
全局变量部分

在这里定义了游戏的状态(等待、运行、结束),其实也可以简化成只有等待和运行,不过为了逻辑上通顺再方便拓展还是这样好一点。width和height是游戏界面的大小。update本来设计是与游戏循环有关,但是实际上没用到。dir、ndir是控制蛇的移动,也在后面说。snakebody、food、space地图上会出现的三种形状,就是蛇、食物、空地。foodX、foodY是食物的位置,snakeX、snakeY则表示蛇,二者都是个数组,length就表示当前蛇的长度。map是当前地图,drawMap本来打算用来辅助渲染,最后还是没用到。debugInfo函数嘛,当时我还不知道有console.log()这玩意儿,就自己写了这样一个函数,用来在页面上显示错误信息。

 

  然后是游戏的初始化:

技术分享
        function Init()
    {
        dir = 3;
        length = 2;

        map = new Array(width);
        for(var i = 0; i < width; ++i)
        {
            map[i] = new Array(height);

            for(var j = 0; j < height; ++j)
                map[i][j] = space;
        }

        snakeX = new Array(width * height);
        snakeY = new Array(width * height);
        for(i = 0; i < width * height; ++i)
        {
            snakeX[i] = 0;
            snakeX[i] = 0;
        }
        snakeX[1] = 0;
        snakeX[0] = 0;
        snakeY[0] = 1;
        snakeY[0] = 0;
           map[1][0] = snakebody;
           map[0][0] = snakebody;

        document.getElementById("msg").innerHTML="Press Space Start";
        Draw();
    }    
初始化部分

在Init函数中完成游戏的初始化。默认蛇一开始长度为2,位于地图的左上角,然后方向朝右。然后把map new成一个二维数组。蛇坐标x、y new成两个数组,大小就是地图的大小。然后调用一次Draw画出默认的样子。Init函数一开始会放在页面的onload。

 

  游戏的渲染部分:

技术分享
function Draw()
{
    var str = "";
    for(i = 0; i < height; ++i)
    {
        for(j = 0; j < width; ++j)
        {
            str += map[j][i];
        }
        str += "<br/>";
    }

    document.getElementById("gameArea").innerHTML=str;
}
渲染部分

就只是简单的把map变成一个字符串放到页面上。

 

  游戏的开始和结束:

技术分享
 1 function Start()
 2 {
 3     state = 1;
 4     update=true;
 5     SpawnFood();
 6     Update();
 7 }
 8 
 9 function dead()
10 {
11     state = 2;
12     document.getElementById("msg").innerHTML="Your Score: " + length + ", Press Space to ReStart.";
13  }
开始和结束部分

游戏开始,变更状态为运行,生成食物并开始更新游戏。游戏结束,变更状态为结束,显示分数。

 

  生成食物:

技术分享
 1 function SpawnFood()
 2 {
 3     loop = true;
 4     while(loop)
 5     {
 6         foodX = parseInt(Math.random() * width);
 7         foodY = parseInt(Math.random() * height);
 8         for(i = 0; i < length; ++i)
 9         {
10             if(foodX == snakeX[i] && foodY == snakeY[i])
11             {}
12             else
13                 loop = false;
14         }
15     }
16 }
生成食物

生成食物就直接随机一个坐标,检查一下跟蛇的身体有没有重合,毕竟食物要出现在一个空地啊,免得蛇太长的时候可能走半天都不知道食物在哪。

 

  主循环:

技术分享
 1 function Update()
 2 {
 3     //0 top 1 down 2 left 3 right
 4     var nextx = snakeX[0];
 5     var nexty = snakeY[0];
 6     dir = ndir;
 7     if(dir == 0)
 8     {
 9         --nexty;
10     }
11     else if(dir == 1)
12     {
13         ++nexty;
14     }
15     else if(dir == 2)
16     {
17         --nextx;
18     }
19     else if(dir == 3)
20     {
21         ++nextx;
22     }
23     for(i = 0; i < length; ++i)
24     {
25         if(nextx == snakeX[i] && snakeY[i] == nexty)
26         {
27             debugInfo("Eat Self" + nextx + "," + nexty + "<br/>head" + snakeX[0] + "," + snakeY[0]);
28             dead();
29             return;
30         }
31     }
32 
33     if(nextx < 0 || nextx >= width || nexty < 0 || nexty >= height)
34     {
35         debugInfo("Eat Wall");
36         dead();
37         return;
38     }
39 
40     if(nextx == foodX && nexty == foodY)
41     {
42         ++length;
43         snakeX.unshift(nextx);
44         snakeY.unshift(nexty);
45         map[foodX][foodY] = snakebody;
46         SpawnFood();
47     }
48     else
49     {
50         snakeX.unshift(nextx);
51         snakeY.unshift(nexty);
52         lastx = snakeX[length];
53         lasty = snakeY[length];
54         //debugInfo("Next Pos:" + nextx + "," + nexty + "<br/>Last Pos: " + lastx + "," + lasty);
55         map[lastx][lasty] = space;
56         map[nextx][nexty] = snakebody;
57     }
58 
59 
60 
61     map[foodX][foodY] = food;
62     debugInfo("food Pos:" + foodX + "," + nexty);
63     Draw();
64 
65 
66         document.getElementById("msg").innerHTML="Your Score: " + length;
67     setTimeout("Update()", waittime);
68 }    
主循环

Update函数是游戏的主循环。本来在Windows程序中他是要放在一个while(true)循环当中的,JS不太一样,想了想用setTimeout以设定好的速率更新游戏。

  在update函数中首先对蛇进行了移动。蛇的移动很简单,根据当前蛇头的位置(也就是蛇坐标(snakeX[0], snakeY[0]) )和当前爬行方向算出接下来到达的位置(nextx,nexty)。首先检查这个位置是否是蛇身体某一部分,如果是,那么表明他吃到自己了,游戏结束。然后检查这个位置是否超出我们设置的地图大小了,如果是,那么蛇撞墙,游戏结束。如果都没有,说明移动是正常的,然后检查这个位置是否是食物的位置。如果是,说明吃到食物,直接把这个坐标放到蛇坐标数组的最前面,也就是蛇头,蛇的长度+1,然后生成新的食物。否则,也把这个坐标放到蛇坐标数组的最前面,然后把蛇的最末端去掉。这样就完成了蛇的移动。

  之后调用Draw更新页面,并显示当前分数。

 

  输入处理:

技术分享
 1 function keyDown()
 2 {
 3     //alert("You Press " + event.keyCode);
 4     //l 37 r 39 u 38 d 40  space 32
 5     if(state == 0)
 6     {
 7         //wait
 8         if(event.keyCode == 32)
 9         {
10             Start();
11         }
12     }
13     if(state == 1)
14     {
15         //0 top 1 down 2 left 3 right
16         //l 37 r 39 u 38 d 40  space 32
17         if(event.keyCode ==  37 && dir != 3)
18         {
19             ndir = 2;
20             debugInfo("Change Dir to left");
21         }
22         else if(event.keyCode == 39 && dir != 2)
23         {
24             ndir = 3;
25             debugInfo("Change Dir to right");
26         }
27         else if(event.keyCode == 38 && dir != 1)
28         {
29             ndir = 0;
30             debugInfo("Change Dir to top");
31         }    
32         else if(event.keyCode == 40 && dir != 0)
33         {
34             ndir = 1;
35             debugInfo("Change Dir to down");
36         }
37     }
38     if(state == 2)
39     {
40         if(event.keyCode == 32)
41         {
42             Init();
43             Start();
44         }
45     }
46 }
47 document.onkeydown = keyDown;
输入处理

这里定义了一个keydown函数处理键盘输入,用document.onkeydown = keyDown;把他作为页面的keydown事件处理函数。

  在这个键盘处理程序里,首先判断游戏状态。等待状态下按下空格键(keyCode:32),调用start函数游戏开始。游戏结束状态下按下空格键,调用init和start函数,游戏重开。游戏运行状态下,按下四个方向键,改变蛇爬行方向。

 

  于是,这就是贪吃蛇全部JavaScript代码了。当然还有页面和样式,这是全部代码:

技术分享
  1 <html>
  2 
  3 <head>
  4 <title>贪吃蛇</title>
  5 <meta charset="utf-8">
  6 
  7 <style>
  8 #msg
  9 {
 10     color:#ff0000;
 11 }
 12 h1
 13 {
 14     text-align: center;
 15     color: #ffffff;
 16     font-size: 64px;
 17     font-family: "Consolas";
 18 }
 19 body
 20 {
 21 
 22     background-color: #dddddd;
 23 }
 24 table
 25 {
 26     border: solid 1px, #66ccff;
 27 }
 28 td
 29 {
 30     border: solid 1px, #66ccff;
 31 }
 32 </style>
 33 
 34 <script type="text/javascript">
 35     var state = 0;//0 wait 1 run 2 over
 36     var width = 40;
 37     var height = 25;
 38     var update = false;
 39     var dir = 3; 
 40     var ndir = 3;
 41     //0 top 1 down 2 left 3 right
 42     //l 37 r 39 u 38 d 40  space 32
 43 
 44     var waittime = 50;
 45 
 46     //△▽○◇□☆●◆■★?◎¤?卍卐
 47     var snakebody="";//
 48     var food = "";//
 49     var foodX;
 50     var foodY;
 51     var space = "";
 52     var snakeX;
 53     var snakeY;
 54     var length;
 55 
 56     var map;
 57 
 58     var drawMap;
 59 
 60     function debugInfo(str)
 61     {
 62         //document.getElementById("debug").innerHTML=str;
 63         console.log(str);
 64     }
 65 
 66     function Draw()
 67     {
 68         var str = "";
 69         for(i = 0; i < height; ++i)
 70         {
 71             for(j = 0; j < width; ++j)
 72             {
 73                 str += map[j][i];
 74             }
 75             str += "<br/>";
 76         }
 77 
 78         document.getElementById("gameArea").innerHTML=str;
 79     }
 80 
 81     function dead()
 82     {
 83            state = 2;
 84         document.getElementById("msg").innerHTML="Your Score: " + length + ", Press Space to ReStart.";
 85        }
 86 
 87     function Update()
 88    {
 89         //0 top 1 down 2 left 3 right
 90         var nextx = snakeX[0];
 91         var nexty = snakeY[0];
 92         dir = ndir;
 93            if(dir == 0)
 94            {
 95                --nexty;
 96            }
 97            else if(dir == 1)
 98            {
 99                ++nexty;
100            }
101            else if(dir == 2)
102            {
103                --nextx;
104            }
105            else if(dir == 3)
106            {
107                ++nextx;
108            }
109 
110            for(i = 0; i < length; ++i)
111            {
112                if(nextx == snakeX[i] && snakeY[i] == nexty)
113                {
114                    debugInfo("Eat Self" + nextx + "," + nexty + "<br/>head" + snakeX[0] + "," + snakeY[0]);
115                    dead();
116                    return;
117                }
118            }
119 
120            if(nextx < 0 || nextx >= width || nexty < 0 || nexty >= height)
121            {
122                debugInfo("Eat Wall");
123                dead();
124                return;
125            }
126 
127            if(nextx == foodX && nexty == foodY)
128            {
129                ++length;
130                snakeX.unshift(nextx);
131                snakeY.unshift(nexty);
132                map[foodX][foodY] = snakebody;
133                SpawnFood();
134            }
135            else
136            {
137                snakeX.unshift(nextx);
138                snakeY.unshift(nexty);
139                lastx = snakeX[length];
140                lasty = snakeY[length];
141                //debugInfo("Next Pos:" + nextx + "," + nexty + "<br/>Last Pos: " + lastx + "," + lasty);
142                map[lastx][lasty] = space;
143                map[nextx][nexty] = snakebody;
144            }
145 
146 
147 
148         map[foodX][foodY] = food;
149            debugInfo("food Pos:" + foodX + "," + nexty);
150            Draw();
151 
152 
153         document.getElementById("msg").innerHTML="Your Score: " + length;
154            setTimeout("Update()", waittime);
155     }
156 
157     function SpawnFood()
158     {
159         loop = true;
160         while(loop)
161         {
162             foodX = parseInt(Math.random() * width);
163             foodY = parseInt(Math.random() * height);
164             for(i = 0; i < length; ++i)
165             {
166                 if(foodX == snakeX[i] && foodY == snakeY[i])
167                 {}
168                 else
169                     loop = false;
170             }
171         }
172     }
173 
174     function Start()
175     {
176         state = 1;
177         update=true;
178         SpawnFood();
179         Update();
180     }
181 
182     function Init()
183     {
184         dir = 3;
185         length = 2;
186 
187         map = new Array(width);
188         for(var i = 0; i < width; ++i)
189         {
190             map[i] = new Array(height);
191 
192             for(var j = 0; j < height; ++j)
193                 map[i][j] = space;
194         }
195 
196         snakeX = new Array(width * height);
197         snakeY = new Array(width * height);
198         for(i = 0; i < width * height; ++i)
199         {
200             snakeX[i] = 0;
201             snakeX[i] = 0;
202         }
203         snakeX[1] = 0;
204         snakeX[0] = 0;
205         snakeY[0] = 1;
206         snakeY[0] = 0;
207            map[1][0] = snakebody;
208            map[0][0] = snakebody;
209 
210         document.getElementById("msg").innerHTML="Press Space Start";
211         Draw();
212     }
213     function keyDown()
214     {
215         //alert("You Press " + event.keyCode);
216         //l 37 r 39 u 38 d 40  space 32
217         if(state == 0)
218         {
219             //wait
220             if(event.keyCode == 32)
221             {
222                 Start();
223             }
224         }
225         if(state == 1)
226         {
227             //0 top 1 down 2 left 3 right
228             //l 37 r 39 u 38 d 40  space 32
229             if(event.keyCode ==  37 && dir != 3)
230             {
231                 ndir = 2;
232                 debugInfo("Change Dir to left");
233             }
234             else if(event.keyCode == 39 && dir != 2)
235             {
236                 ndir = 3;
237                 debugInfo("Change Dir to right");
238             }
239             else if(event.keyCode == 38 && dir != 1)
240             {
241                 ndir = 0;
242                 debugInfo("Change Dir to top");
243             }    
244             else if(event.keyCode == 40 && dir != 0)
245             {
246                 ndir = 1;
247                 debugInfo("Change Dir to down");
248             }
249         }
250         if(state == 2)
251         {
252             if(event.keyCode == 32)
253             {
254                 Init();
255                 Start();
256             }
257         }
258 
259     }
260     document.onkeydown = keyDown;
261 </script>
262 
263 </head>
264 
265 <body onload="Init()">
266     <table>
267         <tr>
268             <td>
269                 <h1 id="title">贪吃蛇</h1>
270             </td>
271         </tr>
272         <tr>
273             <td>
274                 <span id="debug">
275                 </span>
276             </td>
277         </tr>
278         <tr>
279             <td align=center>
280                 <span id="msg">
281                 </span>
282             </td>
283         <tr>
284         <tr>
285             <td>
286                 <span id="gameArea">
287                 </span>
288             </td>
289         </tr>
290     </table>
291 </body>
292 
293 </html>
全部代码

 

运行截图如下:

技术分享

 

JavaScript实现简单贪吃蛇小游戏