本系列实例教程第二趴,作者仅仅想通过一些实际案例,带领大家了解编程,编程其实如此简单。
在学习本教程之前,需要有两个准备,首先,您需要有一点点的编程基础,比如什么是变量、条件判断、循环等。其次,请先玩一玩贪吃蛇这个游戏,如果没有玩过,是不太容易理解其中的一些算法的。
当然,也可以先学习一下第一趴 1小时开发2048,原来游戏如此简单。
我能给您的保证就是,通过本文,您一定可以自己手动编码一个贪吃蛇的游戏,如果不行,请在评论区轰炸我~
- 开发环境准备
- 代码基础准备
- 涉及到的样式
首先,您需要先有一台电脑,如果是手机查看,就算了。。。然后,一个代码编辑器,可以是记事本,也可以是IDEA。这里推荐使用visual studio code编辑器和chrome浏览器。至于visual studio code是啥,请自行百度了。
就是这么简单,开发环境已经准备好了。
width 宽度
height 高度
background-color 设置背景颜色
float 浮动模式
.content 代表某个标签下class属性为content,是一个css选择器,以下是例子:
<div class="content">div>
好了,我们开始进入正题,进入编码环节
- 页面基础框架编写
- 样式编写
- 通过数组展示
- 向右移动第一颗
- 通过方向控制移动
- 多颗如何移动(第一种方法)
- 多颗如何移动(第二种方法)
- 随机出现食物
- 吃到食物如何处理
- 解决随机出现食物bug
- 判断游戏失败:出边界
- 判断游戏失败:撞到自己
- 处理一些其他bug
详见上图,这是一个最基础的html代码,分为三块,页面、css样式、js逻辑,请参考图中的注释。直接浏览器打开本文件,即可看到效果。(可按F12,调出chrome的控制台)
再次说明,html基础标签和结构,请参考html的教程
我们设置整个幕布大小是400px * 400px,每个小块是10 * 10,每行每列就是40个块,一共1600个 。分别定义出蛇身体颜色黑色、蛇头颜色红色、食物颜色绿色。整体样式设置较为交单,具体请参考代码注释,刷新运行,查看效果。
多说几句,关于这个小标题,通过数组展示,其实具有了编程思维的同学,应该很好理解,但是对于没有基础的同学,就有点难了,先看这张图:
游戏中贪吃蛇,就是一条蜿蜒的小蛇,沿着自己走过的路,一步一步往前挪动。我们理解其位在一个二维数组中,连续的一系列方格代表蛇。感觉自己没说清楚,但是不理解也没有关系,编程就是,编着编着就会了。先往下看。
之前通过样式,我们已经清楚了,我们一共是一个40*40,一共1600个格子的二维数组。先来直观的感受下,有多少。
每一行40个0,一共40行,代码冗余了,反正我是看不下去,所以简化它。
这里我们先定义了一个总的gameArr变量,用于存放所有块,是一个二维数组。Array(40)代表生成了一个40位长度的数组。然后,我们遍历这个数据,目前这个数组还是一维的,里面所有元素都是null,所以,我们遍历后,给每个遍历值gameArr[i]又赋值Array(40),然后再次遍历,通过双层遍历,设置gameArr[i][j]等于0,就这样,完成了数组的初始化。请看下图代码。
我们通过数组,在画布上将1600个div呈现出来。双层循环遍历,仔细看代码即可。通过浏览器,将鼠标移动到对应的代码上,就可以看到页面上对应的div呈现出来。
现在,我们仅仅呈现了空白,那么其他值,我们也需要让其呈现出来。
0代表没有任何东西
1代表蛇的身子
2代表蛇头
9代表食物
这些数值的含义,都是我们自己定义的而已,可以改为其他的。
通过判断gameArr[i][j]的值,拼接不同的div。设置是设置好了,但是看不到效果呢。不着急,我们设置一些示例代码即可。请看代码:
然后我们分别设置几个位置为1、2、9,刷新页面,即可看到内容呈现出来了。
好了,准备工作都做好了,现在开始有意思的了。首先我们仅设置1个蛇块,其余的去掉。
首先,我们定义了一个snakeItem作为蛇身,初始化位置为第11行,第11列(js数组下标是从0开始的),然后将对应的gameArr的值,设置为1。snakeItem主要是用于表示蛇的坐标,用于计算。而gameArr是用于最终展示画图的。所以需要根据snakeItem修改gameArr对应的值。刷新页面后结果,请参考图片。
好了,现在,我们需要让其动起来了。这里就不将原理了,设计异步、并行等概念,毕竟我们是实际编程例子,不讲基础(其实是我也说不清。。。)
涉及到JavaScript的定时执行方法,setInterval,该方法涉及两个参数,第一个参数是需要执行的方法,第二个参数是多久执行一次,单位是毫秒。请参考下面的代码
以上代码,会不停的在控制台打印出日志。
关键的来了,如何让小方块动起来呢,向右移动,其实就是snakeItem的列坐标有之前的10,变为11,定时任务中,就是不停的+1。刚刚说了snakeItem是用于计算的,修改了snakeItem后,还要更新gameArr,然后执行drawGame,才能刷新游戏幕布。执行效果如下:
呀,奇怪,动是动起来了,但是变长了,而不是往右移动。
原因是第11列,之前是1,现在12列变为1后,11列还是原来的值1,所以需要重新设置一下。所以在看代码
这里的思路是:先清除画布,然后变到下一个坐标,然后在按新坐标画上去。仔细看代码注释,您就能理解了。
好了,我们的第一个块,终于动起来了,建议设置定时任务的值不要太小,否则你的浏览器会卡死,电脑风扇会狂响。。。不要问我为什么知道的。
上面的代码,我们已经让方块动起来了,但是固定往右的,所以,我们需要加一个变量来代表方向,然后通过监听键盘事件,控制变量,而定时任务根据方向变量,来确定下一个出现的块的位置。请看代码:
方向变量的值,是可以任意定义的,我这里是用的键盘事件中,上下左右方向键所代表的值,方便对应而已,你也可以用1,2,3,4来代表,对应处理的地方,判断处理即可。
这里定义了一个方法,里面添加了jQuery的键盘监听事件,我们仅处理上下左右键,所有,判断等于37、38、39、40的值进行赋值即可。
仅添加方法是不行的,没有地方触发调用,所以我们在启动进入方法里面,调用addListener
先看下之前的代码
gameArr[snakeItem[0]][snakeItem[1]] = 0 // 先将snakeItem位置置为0
snakeItem[1] += 1 // 再向右移动,其实就是列坐标加1,
gameArr[snakeItem[0]][snakeItem[1]] = 1 // 最后设置新的位置为1
第一句和第三句,都是固定的,不需要变化,只有第二句,在方向改变的时候,需要调整。所以,看下面的代码:
通过switch语句,判断方向变量moveDirection的值,然后做出响应。具体请看代码注释。
好了,大家可以刷新页面,然后体验一下根据方向键,小方块移动了,如果速度比较慢,可以将定时任务的间隔值,调低一些,但是不建议小于100,否则会卡的。
我们先来说第一种移动的思路。每一块,按顺序往前移动,前是哪里,主要看方向变量。
我们先定义连续的三个块,代表蛇的身体。
然后修改初始化方法,之前我们只画了一个点,现在我们画3个点。
最后,我们来处理移动。先看我第一步这样写。
先理解这里,我们默认的是往右,所以我们先改39这个分支。
那么向右移动,按之前的思路先清除原先位置,然后所有块向前走,最后再将新的块画上去。先看下效果。向右没问题。那我们先按这样的方式,将上下所有都填好。
向左、向右,挺好,但是向上向下,不对了。整体移动。
我们这样写是有问题的,其实思路上,不应该世界按方向加,而是只有第一个头,按方向加,其余的应该往前覆盖。
将snakeItem1的坐标给snakeItem2
将snakeItem2的坐标给snakeItem3
将snakeItem3的坐标清空
然后snakeItem1设置为下一个坐标
看代码:
仔细理解下代码,思考,为什么先2赋值给3,再1赋值给2。
而不是我们上面说的,先1赋值给2,再2赋值给3。应该比较好理解的。可以自己调下顺序。
这里再说下,不能直接snakeItem3 = snakeItem2,这样是引用赋值了,最后三个都指向一个变量了。大家也可以调下代码试试。
好了,现在第一个思路基本将清楚了,解决最后一个问题,这是三个,如何变成多个呢。这里就不能固定写snakeItem1,snakeItem2,snakeItem3了。要用数组来表示。看下面的代码:
首先修改为数组:
然后,初始化几个蛇身子坐标
修改移动里面方法的处理,也改为数组的方式
其实代码里面的注释已经很清晰了,请多多理解。注意里面第二块,迭代,要从倒数第二个开始后移。多多思考思考。
刷洗下页面,看看效果吧。
也可以自己改改蛇的长度,这个数组及后续的算法,就可以支持任意长度了。
第一个算法介绍完毕,建议多写几遍,熟练贯通。
第一种方法,是所有的块都在往前移动。第二种方式,我们换个思路:
首先有三个块,位置是1,2,3。现在要变为,2,3,4,看前来是不是第一个思路的,2->1,3->2,4是下一个,4->3。
但是,我们观察,首先所有的块都是小黑块,1,2,3在页面上除了位置,其他都一样,那我们换一个思路,将1位置删除掉,数组变成了2,3,再在最前面添加一个4。是不是就行了呢。说起来不是特别清楚,我们直接上代码吧:(以后重新编写的时候,应该会上一些图来帮助理解)
第一,即以当前蛇的第一块为主,根据方向,生成下一个块。
第二,将新生成的下一个块,添加到蛇数组的最前面,作为蛇头。
第三,将蛇数组的最后一块去掉,记得清空游戏幕布的值。
好了,第二个方法完成。第二种方法,移动量比较少,只涉及到新增的下一个块和最后一个块。这样蛇不管有多长,计算量都是固定的。而第一种方法,每一个块都要移动。新多看几遍,琢磨琢磨。
这里我们的蛇头都没有写,修改下代码,看看效果:
第一步修改下初始化位置的代码
其次修改新增的蛇头的代码。要注意,新增的蛇头设置为2,之前老的蛇头要设置为1哟。要不蛇头越来越长,你可以试试看看。
开始写食物了,随机,Math.random()会生成一个0到1之间的一个随机浮点小数。
先添加一个全局的食物坐标存储的变量,一个数组,用于表示食物在幕布上的位置。
然后随机生成两个0到39的整数,赋值给foodItem,设置上幕布在该坐标的值为9,下面判断了,9的值的位置,会显示绿色。
好了现在加好方法了,在哪里触发呢?
1,在初始化后,就触发一次
2,在吃到这个食物的时候触发
我们先来在初始化的位置,调用该方法:
刷新页面后,已经可以看到了,现在你可以控制方向,将蛇引导过去。但是碰得到却吃不掉。
这里,我们仅基于第二种移动算法来进行处理哟。为什么呢?因为我把第一种算法的代码删掉了。。。所以,第一种算法的同学,自己写吧。
还是一样,先说下思路,如何判断吃到食物:
第一:就是蛇身新增的下一个块,如果坐标和食物重合,其实就是吃到了食物。
第二:然后贪吃蛇会怎么样呀,对了,对变长。其实就是长度+1。换句话说,就是不需要丢掉尾巴。
第三:最后,重新随机食物。
话不多说,看代码 :
注释写得很清楚拉,刷新后,可以试试玩玩啦,我们贪吃蛇已经初具样子了。
是什么bug呢,其实就是随机的时候,有可能随机到蛇身体上,这样就不对了。做下判断处理即可,看代码:
游戏已经可以玩了,但是跑到边框,就报错,这样不对。我们要判断游戏结束:出边界。如何判断呢,其实就是新生成的蛇头,坐标超出了边看范围。即行坐标大于39,小于0,列坐标大于39,小于0,都是出界了。所以,看代码:
注意,这段代码的位置,在新坐标出来后,就直接可以判断了。
一样的道理,新生成的块,同自己所有的块进行下比较,看代码:
现在失败后,你试试点击弹出框的确定按钮,发现会一直弹框。是因为我们的这个定时任务会一直不停的继续请求。我们需要加一个变量来控制游戏结束,结束后就不要再触发了。
查看上面三块代码,看看注释,主要注意最后不要缺少一个“}”符号。代码比较长,就没有一起截图了。
好了现在再试试,结束后,就不会一直弹出来了。
现在正在向右移动的贪吃蛇,可以直接向左返回,而且会直接死掉。。。所以我们要限制一下,向右走的,不能向左走,只能上下。其他方向依次类推。看代码注释吧:
好了,到这里为止,我们的整个基础版的贪吃蛇就开发好了,可以自己玩一玩,毕竟是自己的开发成果呢。小有成就感是吧。
这是一个基础版的贪吃蛇,大家可以自己完后完善,包括积分、时间、速度快慢、游戏模式:多个食物、穿墙、障碍等等。以后我会更新高级版本的实例教程,敬请期待~~
谢谢大家耐心看完本教程,如果觉得还不错,请点个赞,帮忙转发一下,谢谢~~
欢迎各位留言~~原创不易,也请大家多多转发,将这么好的教程让更多人看到。后续将推出更多其他详细案例讲解。