一款简单贪吃蛇游戏开发详解(上)
代码的实现比较简单,整个程序由三个类,一组常量和一些游戏逻辑以外的初始化和控制代码组成,总共400多行JavaScript。
游戏开发中的三个类分别是「组成蛇身体的节点」「蛇」「贪食蛇游戏」的抽象,常量用来表示游戏中的各种状态。
先从常量讲起
首先,可以把游戏的逻辑想象成一个不断变换的数据结构,把游戏的界面想象成由一组像素格子组成的长方形,界面渲染程序定时读取游戏数据结构,将数据结构中不同的值表示成不同的颜色并画在游戏界面上。
因此,常量TRANSVERSE和VERTICAL分别代表游戏数据结构的最大边界,也就是游戏界面横向和纵向的像素点个数。
常量LEFT、RIGHT、TOP、BOTTOM分别代表贪食蛇上下左右的走向
常量GAME_START、GAME_STOP、GAME_OVER代表游戏的三个状态,游戏进行中、游戏暂停中、游戏结束
游戏中的三个类是游戏的逻辑实现,相对复杂
贪食蛇蛇身由一系列相互引用的节点组成,是一个链表结构,如下图

每一个节点是SnakeNode类的一个实例


蛇身节点有四个属性
prevDirection 上一刻的蛇身走向
currDirection 当前时刻蛇身走向
next 节点的下一个节点
pos 节点的位置
六个方法
getNext 获得节点的下一个节点
setNext 设置节点的下一个节点
setDirection 设置节点的方向
getDirection 获得节点的方向
computePosition 计算节点下一刻的位置
getPosition 获得节点的位置
SnakeNode.getNextPoint 这个方法是一个静态方法, 不属于节点实例, 它的功能是根据方向计算出某一个坐标的下一个坐标, 比如说10和10是某个节点当前的坐标, 那么它向左移动一个单位后坐标就是9和10;向右移动一个单位后坐标就是11和10,同理向上和向下坐标分别是10,9和10,11。
computePosition需要特点说明一下,它在计算出自身的下一刻的位置以后,还会调用它引用的下一个节点的 computePosition方法,然后下一个节点再次执行相同的操作,一直到蛇身的最后一个节点为止,这就是链表的特性。同时如果方向发了变化,这个方法还会把当前节点的方向同步给它引用的下一个节点,就是靠这一点, 蛇身每一个节点的走向才能一致。
通过这一系列属性和方法就能表示出蛇身的节点特性了。
类Snake是整条蛇的抽象表示,代码如下


这个类有三个属性
snake是蛇的脑袋节点,因为是一个链表,所以通过蛇的脑袋就可以访问到蛇的尾巴,因此,蛇的脑袋就可以表示一条蛇了。
isGameover游戏是否结束
self是实例自身的引用,跟游戏逻辑的表示没有任何关系。
八个公有方法
addNode 给蛇身增加一个结点,当蛇吃到食物时会调用这个方法,这个方法会把新的节点追加到最后一个节点(蛇尾)的后面。其中局部变量reverse是用来计算新节点的位置用的,假如当前节点的方向是向右的,那么下一个节点肯定在当前节点的左边,以此类推, reverse变量就是当前节点相反方向的值,细节请结合代码理解。
getAllNodePos 获得蛇身所有节点的位置。
getLength 获得蛇身长度(蛇身节点个数)
isGameover 游戏是否结束
move 移动蛇身,调用一次整个蛇身便移动一下,这里的移动仅仅是数据结构变化,具体效果需要将数据结构结果渲染至页面。
setDirection 设置蛇的游动方向
getHeadPos 获得蛇身的第一个节点(蛇头)的位置
getHeadDirection 获得蛇(蛇头)游动的方向
二个私有方法
checkGameover 检查游戏是否结束,分别检测游戏的第一个节点是否落在 TRANSVERSE和VERTICAL常量定义的范围之外(撞墙)和是否落在蛇身节点的位置之上(咬到自己)。
getLastNode 获得蛇身的最后一个结果
通过SnakeNode和Snake这两个类,便抽象出了贪食蛇的结构和特性,但是现在这条蛇只是一个逻辑结构,是不会动的, 更不能玩。接下来我们便让这条蛇游动起来, 还可以控制它的方向, 让它去觅食并越长越长越游越快。




