开发游戏引擎(7)

 

8. 添加其他函数

我们还将在基类中添加一些更加深入的功能集,供引擎或者游戏自身使用。

首先,要添加的是一个随机数生成器。该生成器只是.NET System.Random类的一个实例。通过引擎访问随机数生成器会有两个优点:第一,每当需要随机数时就可以调用它,而不用创建本地实例,从而使代码能够更加简单;第二(也是最有用的),我们有机会为随机数生成器指定一个固定的随机种子。采用固定的随机数种子,使应用程序生成的随机数字每次都是同一个序列,这样就可以重复同一个游戏场景来进行测试(不考虑与玩家的交互)。

还要添加一些代码,用来在游戏运行期间返回游戏的帧率(使用FramesPerSecond属性)。它记录了每一秒中屏幕上的图形更新次数。我们将尽量获得帧率的最高值,因为帧率越高,动画就会越平滑。当帧率降为很低时,游戏会看上去很卡,所以对帧率值进行监视是很有用的。

最后,还要有另一个对象管理函数RemoveTerminatedObjects。当某个对象不再被游戏所需要时,我们就为它设置一个标志,告诉引擎该对象将要终止了。RemoveTerminatedObjects函数会从对象集合中将所有包含该标志的对象删除。对象必须通过这种方式来删除(而不是马上从集合中将它们删除),因为我们需要在它们被销毁之前进行清除;在Advance函数的最后来执行这个任务。在本章后文中介绍优化图形渲染时将解释为什么需要用这种方式来删除对象。

4.2.2  CgameObjectBase类

下面对CGameObjectBase类进行概要的介绍:

● 目的  显示游戏中的图形对象。

● 类型  抽象基类。

● 父类  无。

● 子类  专门用于游戏的图形API实现,例如用于GDI引擎。

● 主要功能

● Xpos、Ypos、Zpos、LastXPos、LastYPos、LastZPos  用于定义对象位置的属性。

● IsNew, Terminate  用于定义对象状态的属性。

● Render  允许将对象绘制到游戏中。

● Update  允许对象自己进行移动并产生动画。

有很多对象都继承于游戏对象,所以我们来看看这些对象的基类。

CgameObjectBase类是另一个抽象基类,我们所有实际的游戏对象都将从它继承。在其构造函数中要传递一个对CGameEngineBase游戏引擎(或者是其子类)的引用。该对象中存储了一个私有的类变量_gameEngine,通过访问权限为protected的GameEngine属性可以访问它。这样所有的对象都可以在其运行平台中访问游戏引擎实例。

1. 对象的位置

CGameObjectBase类中包含了用于跟踪对象位置的一系列属性值。我们保存每个对象当前的x坐标、y坐标和z坐标。在第3章中已经介绍过x坐标和y坐标;z坐标用于表示对象在第三个维度上的位置,在屏幕中但不在屏幕上(事实上z轴应与屏幕垂直)。在本书后文中介绍用OpenGL ES开发3D图形时,z坐标才会扮演重要的角色。

对于每一种坐标,我们都会将对象当前的位置及先前的位置保存起来。这样做有两个重要的原因。首先,有两个位置才能判断对象是否移动了。本章后文中会介绍如何使用该信息使游戏引擎在渲染时更加有效。其次,将两个位置都保存的话,能使对象在这两个位置之间移动时更加平滑。在第5章中讨论游戏所用的不同的计时方式时将会用到它。

位置的值使用以下6种属性表示:Xpos、Ypos、Zpos、LastXPos、LastYPos以及LastZPos。前三个属性值将返回对象的当前位置;它们被定义为虚属性,如果需要,将在继承对象类中被重写。其他三个属性用于返回对象的上一个位置。

与位置属性相关的是UpdatePreviousPosition函数。它将所有对象的当前位置属性中的值复制到先前位置属性中。每当需要更新对象的位置时,在计算出对象的新位置之前,就可以通过游戏引擎来调用该函数,这样可以确保对象的先前位置属性准确而及时。

所有这些与坐标相关的属性都用float类型来存储值。这似乎不太必要,毕竟我们不能绘制半个像素,为何要用分数来标志像素的位置呢?

虽然不能在非整数位置上绘制对象,但用非整数来更新其位置还是很有用的。例如,您想在屏幕上以非常慢的速度显示太阳的移动轨迹,就会发现,如果每帧移动一个像素,那么移动的速度会过快。与通过实现复杂的逻辑使在若干帧后才移动一次相比,现在可以按照0.1或是0.01的增量来移动。这样就将速度降到原来的1/10或1/100,不需要任何额外的代码。

当以后开始使用OpenGL ES时就能发现这样做的另外一个好处了。OpenGL ES所使用的坐标系与屏幕上的像素没有对应关系。因此,以分数的方式来修改对象的位置实际会对其显示位置产生影响。

读书导航