感谢『简书 ID: 何小成』友情提供
http://www.jianshu.com/p/dcebe85e0620
贪吃蛇相信大家都玩过。我对贪吃蛇的最初印象就是在电子词典上,一只像素蛇在屏幕游走,饥渴难耐,看见豆子就要去吃,每吃到豆子就会长一节,当蛇的身体越来越长,它才发现这个世界变了,每一步都寸步难行。
无论蛇头触碰到屏幕边界还是自己身体,游戏就结束。这款游戏应该是比较经典的一个童年记忆。刚接触游戏开发的人也许会喜欢以这款游戏入手,因为贪吃蛇包含了很多游戏开发中的原理,难度也不大。
身体关节
贪吃蛇的实现有多种方法,但今天,我想用面向对象的思想进行设计。任何程序开发都离不开面向对象的思想,通过面向对象我们能把很多抽象问题具象化,方便我们解决很多问题。而在贪吃蛇中,面向对象的思想依然实用。
在贪吃蛇中,我们可以把一条游走的蛇的每个关节当做是一个对象,而蛇本身是由多个关节组成的整体,当每个关节在移动时,我们就能看到蛇的移动,每个关节的位置以及移动方向都跟它的上一个关节息息相关,那么我们就可以把关节与它的上一个关节关联起来,实现如下结构:
移动方向
如上所说,按照上面的关节关系来实现,那么蛇的移动方向就是与父节点的移动方向相关联。每一个关节应该有一个当前移动方向和下次移动方向,每一步移动,都是跟着当前移动方向走的,而父关节当前移动的方向即为子关节的下次移动方向,这样,只需要调整蛇头关节的下次移动方向,整条蛇就能顺着各自的父关节方向移动,蛇的移动方向图如下:
项目结构
按照前面的设计,我们大致可以划分为游戏场景类和关节类。
进入
游戏场景类
,再将一些全局的变量单独存在一个类中,项目结构可划分如下图:
项目结构图
全局变量类
游戏中的全局变量,提炼为一个全局变量类,其中参数可以根据需求灵活变动配置
关节类
按照以上设计的结构,每一个关节对象都应该包含蛇的当前方向、下次方向和蛇的父节点三个属性,代码如下:
上面说的,关节的位置跟它的福关节的位置是息息相关的,那么初始化的时候,我们就需要根据父关节的移动方向来进行次关节的位置设置。这部分代码,我们可以放在onEnter方法中,代码如下:
有了这三个属性,每一个节点还应该有最重要的游戏逻辑——move方法。每一个关节分别调用move方法,从游戏场景中就能看到整条蛇按照预定方向进行移动,而整条蛇的运动方向就是跟着头部关节的方向走,头部关节的方向则通过点击屏幕区域控制。
在move方法中,我们需要做以下事情:
同时,如果是头部关节,我们还需要判断以下三个临界条件:
其中1、3条件达成,则判定游戏结束,2条件达成,则能增加游戏分数,并且游戏继续。move方法代码如下:
游戏场景类
在游戏场景中我们需要以下几个变量:
在cc.Layer的构造函数中对以上变量进行初始化,代码如下:
之后,我们首先需要在场景中绘制出一条蛇,初始化定义为1个头部关节,5个身体关节,由于我们对关节类做了很好的封装,所以初始化一条蛇的代码很简单,我们在onEnter方法中进行初始化,如下所示:
初始化完了之后蛇是不会动的,如何让它动起来呢,我们就要用到在关节类中封装的move方法了,我们每隔一个时间,对所有的关节类执行一次move方法,就能实现蛇的移动,首先在onEnter中添加定时任务:
在这个snakeMove定时调用的方法中,我们要写出所有关节移动的逻辑,在这个方法中,我们需要完成以下几件事:
代码如下:
目前为止这条蛇只会按照我们初始化的方向一直走到碰壁,然后游戏结束的,如何改变蛇的运动轨迹呢?前面说到了,蛇头部节点的下次移动方向的改变,即可对整个蛇的移动轨迹进行改变,这里我们可以通过点击屏幕实现蛇头的下次移动方向的改变。
首先在onEnter方法中添加触摸事件监听:
然后在onTouchBegan方法中实现点击事件,我们允许点击有一个10像素的误差:
我们只差最后一步,就是蛇要吃的星星。我们可以在屏幕中任意位置随机产生一颗星星(又或者叫豆子,这都无所谓),只要这个星星满足以下条件,那么它就可以被绘制出来,否则我们需要重新随机这个星星的位置:
代码如下: