一个基于React实现的贪吃蛇消灭怪物的游戏
贪吃蛇游戏 相信大家都玩过。在没有安卓手机的时候,它应该是我们最大的乐趣了!
这个游戏是仿照传统的贪吃蛇游戏实现的,并添加了发射子弹消灭怪物的功能。它可以支持多种平台,在PC上可通过键盘操作,在移动设备可通过触屏操作。
- 首先思考游戏的布局,将游戏界面分割为多个小块,游戏中蛇,食物,怪物都对应其中的某些块。
由于这些角色的坐标都分x,y两个方向,为了方便起见,我的坐标用x*列数+y的数值来表示。 定义一个数组来记录这些小块(即坐标)的状态,初始为null,当表示蛇用‘S’,表示食物用‘F’,以此类推。 在render界面时,通过判断对应坐标的状态来生成相应的样式。
-
以前在学算法时,曾经通过两个数组来定义方向,这里亦是如此。初始化两个数组,分别表示X轴和Y轴坐标发生的变化(即+1,-1或者不变)
-
初始化角色,食物的长度为1,用一个变量记录它的坐标,蛇的长度是变化的,用数组记录每一截的坐标。
更新用于记录状态的数组,标记出角色的位置。
-
每一个周期,游戏都会根据当前状态进行一系列运算,计算出下一个状态,并绘制到屏幕中。
-
重点还是运算过程,首先计算出蛇的下一个位置,判断该位置的状态,如果为自己本身,设置游戏结束,如果为食物,长度增加一,如果为null,则前进一步。然后监听键盘或者触控事件,改变当前的方向。
-
基本功能差不多就实现了,接下来就是添加怪物了,怪物的初始化和食物一样,只要不和屏幕中已经存在蛇或者食物的坐标冲突即可。比较有难度的还是子弹,添加监听空格事件,将蛇的头部点加入到子弹的数组,蛇对应的数组减一。子弹的运动和蛇的运动相似。考虑到子弹的运动速度快,设置了tick频率,子弹运行两次,蛇前进一次。当子弹遇到怪物时,子弹数组清空,子弹消失,怪物重新出现,如果没有碰到怪物,到屏幕边缘消失。
-
添加上分数设置,在消灭怪物时分数增加。到这里游戏的功能差不多就都实现了。
-
接下来就是响应式的问题了。本来是想通过CSS在不同范围的屏幕大小下显示不同的布局,但是考虑分类情况有点多,运行效果还不一定满意,就决定使用js通过获取当前屏幕的大小计算对应的游戏区域大小。
-
触屏控制的实现,这个是参考慕课网上的课程,计算手指滑动的方向去改变蛇运动的方向。
-
优化。将蛇,食物,子弹,怪物设置为单独的div,通过定位确定其在游戏区域的位置,省去了每次都要循环对游戏区域中的每个块进行加载耗费的资源,使游戏运行起来更快。
- 上键失效。当键盘控制游戏时,按上键蛇并没有改变方向向上。
原因:判断条件的失误,在设计的时候通过下标来判断方向,却没有考虑0表示上会使得‘上’条件不成立。 方案:重新改变判断条件。
- 蛇反方向运动问题。当正好按键按到蛇当前运动方向的反方向时,蛇会因为判断碰到自身,导致游戏结束。
方案:添加按键方向与当前方向相反时按键失效的判断。
- 子弹碰到食物时,食物会消失
原因:子弹的移动会改变它前面的位置的状态,如果为食物,即将食物对应的状态改变,导致食物消失 方案:当计算到子弹下一个对应位置为食物时,将下一个的取值定位为跨过食物的下一个,这样的处理有点粗暴,不过实际去看不是很明显看出。
- 在怪物的前一个位置发射子弹时,怪物没有消失,并且碰到怪物时,游戏没有结束
原因:当子弹碰到怪物时,怪物数组清空,但是记录状态的数组值没有改变,即不同步 方案:改变判断顺序,先判断怪物,在改变状态数组
一个看似简单的游戏中也深藏着很多逻辑的想法,实现的不易。 利用React开发网页版游戏,利用React每次改变State时重新加载的特点,计算每一个时间点对应的状态,渲染之后再计算下一个,以此类推即可。 开发过程要从简单功能逐步添加实现,要仔细考虑细节方面的问题。
该游戏在chrome浏览器上运行没有问题,手机浏览器种类比较多,暂时还没有兼容。