我们都知道,我们游戏的场景之间的切换,都是依靠一个栈来实现。一个很简单的例子,当你启动游戏的时候,将标题画面的内容压入一个栈,当你选择开始游玩,将游戏的内容继续压入,当你结束游戏,游戏内容从栈中弹出,这时你又会重新看到原来的那个标题画面,我们想要达成这个简单的压入弹出。
那想法就很简单了,写一个栈!然后把各种界面都整成同一种通用类型的子类往里面压入不就完事了?行,开写。
StateStack
类:
我们都知道,我们游戏的场景之间的切换,都是依靠一个栈来实现。一个很简单的例子,当你启动游戏的时候,将标题画面的内容压入一个栈,当你选择开始游玩,将游戏的内容继续压入,当你结束游戏,游戏内容从栈中弹出,这时你又会重新看到原来的那个标题画面,我们想要达成这个简单的压入弹出。
那想法就很简单了,写一个栈!然后把各种界面都整成同一种通用类型的子类往里面压入不就完事了?行,开写。
StateStack
类:
为了让我们能够很轻松地用简单的几句话控制音乐的播放、音量还有暂停,以及游戏音效的随意施放,我们有必要写两个类来分别处理音乐和音效:
先给自己准备好的每一个音乐都准备好独特的id,在这里我们实际上还没有准备任何的音乐,所以我们这里只放上一个MusicCount用来占位。
然后就是MusicPlayer类:
在这里需要注意的是,音乐和其它文件是不一样的,音乐文件一般比较大,因为音乐很长,所以SFML的打开方式并不是像其他类型的文件一样,而是根据音乐播放的进度选取文件当中的某一段读入,在之后销毁掉换成另一段,也就是说这个音乐播放时需要保证文件一直能够访问到。
有的时候我们还是需要获取某个东西的绝对位置,以方便我们进行碰撞检测等操作,所以,我们需要根据4中的树形编排方式再实现一点点东西:
这样我们就也可以很轻松地借助相对位置得到绝对位置了。
在游戏中我们时常能见到某个实体围绕另一个实体做运动,它实际上是以这个被围绕的实体为参照的相对位置,如果直接使用绝对位置来计算固然可以,但是十分麻烦。比如某游戏中主角有一个闪电球始终环绕着旋转,这时我们既要考虑主角的运动情况,还要考虑到球绕着主角的旋转情况,计算起来非常地繁琐。
又没有更好的方法可以解决这个问题呢?
我们可以用“树”的结构来解决这个问题,依照上文的例子,我们把闪电球作为子节点连接到主角上,这时,我们便只需要考虑球的旋转就行,其他的位置已经由主角决定好,就相当于,坐标的变换从父节点到子节点一路叠Buff,用这种结构,我们甚至能为这个闪电球再添加围绕它的别的什么球。
在游戏每帧的更新过程中对所有不同类型的实体,还有背景、GUI等进行更新是在是太麻烦了,而且,除了之前写好的SceneNode之外,你还需要东西来分类存储他们。
那太麻烦了,不好用,又没有更简单的?
我们引入指令系统,将指令传入整棵树,让它自行选取符合条件的实体进行更新。每帧我们根据用户的输入情况以及游戏的整体情况决定需要进行哪些更新,然后往里面扔就完事了!
搭配上SFML的内容,我们先写出类似学习SDL时的游戏结构:
这件事做起来很轻松,不是吗?
但是,这并不是很好看。我们为什么不把它重新包装一下,让它更好理解呢?这样如何?
我们尽量把这些过程都拆开,分而治之,不然到时候很有可能搞不清自己到底在做什么。
具体的函数实现就不放在这了,你自己心里面应该有数。
把文件一个一个声明并且读入固然十分有效,但是太麻烦了,根本不好用。
所以为什么我们不自己写一个类,让他来控制所有文件的存取呢?我们可以给每一个加载的内容都带上一个特殊的id,想要的时候再通过id把它取出来,这样既能保证文件只被加载一次,同时也能让存取的步骤更加的简单:
load函数的实现:
get函数的实现:
又到了和 SDL
一样痛苦的配环境环节!
SFML
(Simple and Fast Multimedia Library) 是一款非常好用的图形界面库,你用得到的功能(包括网络),它基本上都考虑到了。而且它具有非常良好的跨平台能力,它在各大平台上都能顺利地运行,且能够完美地适配不同的屏幕分辨率和尺寸,能让你获得最舒适的游戏体验。
(所以为什么不用 Godot Engine
或者 Cocos2D
之类的呢?)
我可不管,我就想用这个。