最近都在学习js,学习间隙总想拿点项目练习,而贪吃蛇作为一个简单的小游戏正适合。相信大家都玩过贪吃蛇,我记得我第一次看到这个游戏是在小学的时候。当时家里买了个新手机,黑白的屏幕,点开游戏映入眼帘的就是贪吃蛇。虽然当时手机屏幕还是那么的小,分辨率还是那么低,但是这个游戏还是让我不亦乐乎,好了扯远了,下面我们就用js实现一下这个游戏吧!
首先,作为一名初学者,我搜索了一下网络上现有的资料,然后看到了一段相关的代码,虽然时间已经很久了,但是我试玩了一下,觉得界面很清新,很喜欢,所以就决定按此来借鉴学习了。
他的代码是没有分开的,所有的代码都写在了一个文件里。我在后面会把它分开来,然后,他的代码是没有按面向对象来写的,我也会把它改进。好了下面开始正式讲解。
我们先理一理游戏的逻辑:
- 建立一个游戏的地图
- 绘出蛇和它的食物
- 让蛇动起来
- 增加一些判定机制
- 增加一些其他娱乐元素
第一步
要建立一个游戏的地图。此处的前提是有一个html页面,我们的重点不是如何编写html和css,所以我就直接给出我最后的代码了。此代码是根据我上述提到的代码改的,其中添加了一部分元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>贪吃蛇</title> <link rel="stylesheet" href="snake.css" /> <script type="text/javascript" src="snake_class.js" ></script> </head> <body> <div id="say">贪吃蛇</div> <span class="best">最高分:<strong id="best_score">0</strong></span><br /> <span style="float: right;">方向键:控制方向,空格:暂停/开始</span> <div id="snakeWrap"></div> <div id="help"> <span class="box food"></span><span>绿色加分</span> <span class="box block"></span><span>灰色路障</span> <span class="box skate"></span><span>蓝色加速</span> <span class="box brake"></span><span>红色减速</span> <span style="float:right">目前得分:<strong id="score">0</strong></span> <input type="button" id="btnStart" value="开始游戏" /> <div id="size"> <p style="width: 150px;color: white;float: left;">请选择游戏地图大小:</p><br /> <form style="width: 200px;float: left;"> <input type="radio" name="size" value="20" checked="true"><span style="float: none;">20*20</span></input> <input type="radio" name="size" value="40"><span style="float: none;">40*20</span></input> <input type="radio" name="size" value="60"><span style="float: none;">60*20</span></input> </form> </div> </div> </body> </html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| * { padding: 0px; margin: 0px; } body { background: #333; -moz-user-select: none; font-size: 12px; text-align: center; } table { margin: 20px auto 10px auto; overflow: hidden; border-collapse: collapse; } td { width: 20px; height: 20px; border: 1px solid #ddd; background: #f4f4f4; } .cover { background: #39c; } .food { background: #093; } .block { background: #333; } .brake { background: #f00; } .skate { background: #00f; } #help span { float: left; margin-right: 10px; } #help .box { width: 15px; height: 15px; margin-right: 5px; border: 1px solid white; } #help { width: 420px; margin: 0 auto; line-height: 17px; } span{ color: white; } #say { margin-top: 20px; margin-bottom: 20px; color: white; font-size: 14px; } #snakeWrap { margin-top: 0px; } #btnStart { clear: both; width: 100px; height: 30px; margin-top: 10px; margin-right: 50px; padding: 0; background: #bbb; color: #222; border: 1px solid #fff; border-bottom-color: #000; border-right-color: #000; cursor: pointer; float: right; } .best{ font-size: 20px; margin: 40px auto 10px auto; } #size{ margin-top: 10px; width: 200px; height: 50px; float: left; margin-left: 20px; }
|
上面的代码分别复制、黏贴后就可以生成一个基本的网页了(注意我在html中的注释,当心css文件的文件名和位置),但是,我们可以发现里面没有我们上面提到的任何一个逻辑,那就对了,剩下的所有逻辑我们都要通过js文件来完成,从此处我们也可以看到js在前端技术中是多么的强大。
现在我们还在讨论第一步,好的我们继续。游戏的地图也就是一些大小相同的方格,一个个的生成肯定是不实际的,因为这样很难管理,如此规则的矩形阵列怎么规模生成呢?表格对不对!?是的,表格除了一般用来放文字之外其他特征都很像,那么我们只要不放入文字并设置好大小不就行了?好的,接下来就可以做了。还有我们要注意一点,我们表格的位置也选好了,就是html中id是snakeWrap
的模块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| this.initGrid = function(target){ if (this.table) { $(target).removeChild(this.table); } this.table = document.createElement("table"); var tbody = document.createElement("tbody"); for (var i = 0; i < this.HEIGHT; i++) { var row = document.createElement("tr"); for (var j = 0; j < this.WIDTH; j++) { var col = document.createElement("td"); row.appendChild(col); this.gridElems[i][j] = col; } tbody.appendChild(row); } this.table.appendChild(tbody); $(target).appendChild(this.table); }
|
上述就是具体代码,其中的this
是最后类封装是加上的,现在你可以忽略,把他们都理解为全局的函数或者变量。其中的主要思想就是:利用DOM技术,按表格标签的结构生成表格结点,再绑定到id为target
的元素上,也就是目标位置。其中开头的代码是在已有表格时限删除现有表格的,此时不用太注意。我们需要注意一下gridElems[i][j]
,这是后续控制的关键,这是一个二维数组,下面会给出代码,还有一个$
运算符,是一个简化代码的函数,一起给出,看一下就明白了。
1 2 3 4 5 6 7 8 9 10 11
| function multiArray(m, n) { var arr = new Array(m); for (var i = 0; i < m; i++) { arr[i] = new Array(n); } return arr; } function $(id){ return document.getElementById(id); }
|
第二步
我们需要在创建好的地图上绘出基本的游戏元素。玩过的都知道,蛇我们可以简化为一系列连续的色块,而食物我们可以用一个其他颜色的色块代替。我们这里有一个问题,如何控制颜色?首先,有一个基本的思想,就是我们通过设置上述表格的className
属性来简化问题,这样只要我们在css中事先设计好颜色就好了。还有一个关键点,就是上面我们刚提到的gridElems
,它连接到每个表格元素,所有的设置都要靠它。
1 2 3 4 5 6 7 8 9 10 11 12 13
| this.initSnake = function (){ this.talk("贪吃蛇游戏开始啦~"); $("score").innerHTML = this.score; this.snake_pos = new Array(); var snake_head_dot = randdot(this.carrier, 0, this.len - 1, this.HEIGHT, Math.floor(WIDTH/2)); for (var i = 0; i < this.len; i++) { var x = snake_head_dot[0]; var y = snake_head_dot[1] - i; this.snake_pos.push([x, y]); this.carrier[x][y] = "cover"; this.gridElems[x][y].className = "cover"; } }
|
上述代码也经过了封装,有关this
的都是类的属性或者方法,现在只要简单理解为一些函数或者变量就可以了。我们的重点从创建一个Array开始,其用来存蛇的身体每点的坐标,randdot
是一个用来生产随机点的函数,下面会给出。carrier
也是二维数组,来记录地图的使用情况,其一般与gridElems
联动。最后一行就是对表格的控制。最前面的两行是一些交互,现在不用理解。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function randdot(carrier, startX, startY, endX, endY){ startX = startX || 0; startY = startY || 0; endX = endX || this.HEIGHT; endY = endY || this.WIDTH; var x = Math.floor(Math.random() * (endX - startX)) + startX; var y = Math.floor(Math.random() * (endY - startY)) + startY; var dot = [x, y]; if (carrier[x][y]) { return randdot(carrier, startX, startY, endX, endY); } return dot; }
|
这个函数需要传入carrier
来保证不会重复利用,而其他的参数就是起始、结束位置。代码的前几行类似默认参数设置,我试过了直接写在形参的位置,但是chrome好像不认,所以还是按照原代码写了。添加食物我们可以结合后续要添加的各种要素统一创建一个函数,但是基本思想和上面是一样的。
1 2 3 4 5
| this.addObject = function(type){ var pos = randdot(this.carrier); this.carrier[pos[0]][pos[1]] = type; this.gridElems[pos[0]][pos[1]].className = type; }
|
可见我们用了type
来指代要添加的名称,此名称和css相关控制显示,然后其他的就和上面的一样了,联动的修改carrier和gridElems。到这里第二点的逻辑就实现了。
好了,今天先讲到这里。
版权:本文采用以下协议进行授权,自由转载 - 非商用 - 非衍生 - 保持署名 | Creative Commons BY-NC-ND 3.0,转载请注明作者及出处。