本文仅供个人记录和复习,不用于其他用途
游戏效果展示
游戏流程设计
- 开始界面:三个难度选择以及退出按钮
- 游戏界面:加载对应的关卡
- 关卡生成:只生成一个跑道
- 英雄生成:加载英雄的动画
- 障碍物:不断地刷新障碍物
这里要说明一下,由于跑道都是一样的,所以我们只需要编写一条跑道的代码,然后交由游戏主界面进行生成即可。
LayerStart
游戏的开始界面,用于选择关卡。
LayerStart.h
|
|
游戏开始场景,很简单,生成四个按钮,然后设置对应的回调事件即可。
LayerStart.cpp
|
|
LayerMain
的创建方法需要我们提供一个参数,在这里就是对应的难度,其他的不再多说。
LayerMain
游戏主场景,也是我们玩游戏的界面。
LayerMain.h
|
|
这里我们使用的是有参数的创建方法,接受的是LayerStart
传递而来的难度系数(1、2、3)。_layerCount
用于记录当前所选择的难度。
LayerMain.cpp
|
|
这里的工作其实就是把_layerCount
初始化,然后创建对应个数的LayerOne
,也就是跑道。LayerMain
继承的是LayerColor
,这里调用LayerColor
的初始化方法,将层的背景颜色改为白色。
Hero
用于生成英雄,并且加载动画。
Hero.h
|
|
Hero.cpp
|
|
这里只需要一个初始化方法,加载英雄的动画,并且执行这个动画即可。
Block
用于生成随机的障碍物。
Block.h
|
|
Block.cpp
|
|
Block
的长和高被固定在10-39之间,然后我们将方块设置成黑色,并且调用定时器让这个方块每帧往左移动6。这里我们可以看出,并不是英雄在动,而是方块在不断地往前移,造成了英雄移动的假象。rand()
是标准库函数,用于生成随机数。其实我们在使用这个函数时应该设立随机数种子,否则它生成的都是固定的数。
LayerOne
LayerOne
用于生成一个跑道,然后加入英雄和障碍物,并且进行碰撞检测。
LayerOne.h
|
|
LayerOne
的创建方法接受一个参数,不过这个参数不是代表要生成多少个跑道。前面已经说了,LayerOne
只生成一条跑道,所以这里代表的是第几条跑道,这样能够方便我们设置跑道所处的位置。randFrameCount
和curFrameCount
都是和随机生成有关,后面会讲到。
LayerOne.cpp
|
|
LayerOne
同样继承自LayerColor
,主要是设置背景颜色为白色。这里我们将层的大小设置为长320高150,由于我们需要显示其他的内容,所以不把层的高度设置成窗口高度的1/3。层的位置设置就根据传入的layerCount
,从下到上依次设置。addGround()
其实就是在层的底部生成一条黑色的跑道,addHero()
就是加入Hero
类。
关于触摸事件,这里要说明一下。由于我们只编写了一个LayerOne
,当这个类被多次调用时,哪怕生成的跑道处在不同的位置,只要点击其中一条跑道,其他的两个都会执行回调事件。为了避免这种情况,我们对当前触摸点进行了判断,所以,只要触摸点处在当前层中,就会执行跳跃动作,而其他的层由于没有包含触摸点,所以不会有反应。
其实这里比较关键的是update()
,我们用resetFrameCount()
生成了一个30到69之间的随机数,然后在update()
将curFrameCount
不断递增,这样就做到了随机生成障碍物,并且使得障碍物没有那么密集(因为最快也要30帧才能生成一个)。一旦我们的障碍物生成了,就需要再次调用resetFrameCount()
,开始新一轮的递增。接下来是英雄的碰撞检测,我在之前的章节已经提到过了。
总结
至此,我们完成了《一个都不能死》的游戏开发。项目实战进行到了第四个,我们会发现游戏开发需要严谨的架构和逻辑。这几个游戏虽然不大,但也不代表我们可以想怎么写就怎么写。这款游戏是一个很好的例子,它的层与层之间都分隔开来,一个层只完成一个工作。我们在编写函数时,也经常被教导说一个函数只完成一个工作。这不是多此一举,而是为了让代码结构清晰明了。