游戏构思

在你开始游戏屏幕和游戏逻辑之前,快速浏览一下这个游戏的原始构思,这样你能理解为什么某些东西实现了而有些却没有。在游戏的主要功能实现后,一些部分才在后面添加。这方面的一个例子是阴影映射,这始终是游戏引擎的复杂部分,因为你要花费大量的时间进行调整,直到它看起来正确。还有些东西必须跳过或故意排除在外,因为它们实在太复杂,在短时间内很难实现。最好的例子是道路上的障碍物(例如柱子),如果玩家不小心驾驶就会撞在障碍物上(见图14-2)。

1
图 14-2

这一想法的主要问题是如何有效率地设置障碍栏。这个游戏没有关卡编辑器或赛道编辑器。所有赛道都是由采样点生成的,很难在3DS Max中设置障碍物。测试这些物体并更新碰撞检测系统会产生更多的问题。在早期测试版中我使用了道路立柱,并将赛道放在立柱上(见图14-3)以测试这个使用障碍物的想法,但它看上去并不十分令人信服,而且只在赛道上开车已经是够难的了。一个更好的解决办法是添加如道路标志,交通灯,垃圾箱等可以破坏的物件,但上一章中你已经看到物理引擎不能够处理许多不同的物体,它只检查汽车与护栏的碰撞,并进行相应的的物理计算,仅此而已。

2
图 14-3

经过几次单元测试后,我决定放弃这一想法,将精力花在游戏的其他部分。我还添加了隧道和一种简单的方法来设置道路附近的棕榈树,标志,路灯等,并添加一个很好的技术,它能在赛道附近自动添加场景物体。

下列的文字直接来自于最初的游戏构思,这个构思确定于2006年8月,是在2006底开发这个赛车游戏之前。请注意,这个构思写于第一个XNA的beta版本发布以前,那时我还不知道XNA的许多细节。

游戏理念

这个赛车游戏是一个简单的3D赛车游戏。玩家能看到前面的赛车并能使用Xbox手柄或鼠标或键盘直接控制赛车。游戏的主要目标是尽可能快的到达终点并绕过所有障碍物。碰撞不会伤害玩家,但赛车会减速导致完成时间大大增加。玩家不会游戏结束,他只需花很长时间完成赛道。有3个不同难度的赛道,每个赛道都有一个排行榜。(注:这本书中的赛车游戏版本没有实现多个轨道,也没有最高分数或奖杯,请查看XNA的赛车游戏初学者工具包获取更多细节和附加功能)

这个游戏的图形(见图14-4)借鉴了如赛道狂飙,GT赛车,极品飞车等类似的游戏。显然,这些游戏花了很长时间开发并有很漂亮的图像,这在短时间内是不可能完成的,因此这个游戏着重于创建一个简单易学的、只有基本功能的赛车游戏。主要图形的主题是位于城市(显示街道,一些简单的建筑物,以及一些树木)。地面使用一个简单的二维图形,赛道是从二维图像自动生成的(使用特定间隔的点),使用高程图创建山较难,而创建赛道更难。 (请注意,这一想法后来被放弃,现在游戏中导入的是真正的三维数据。)

3
图 14-4

在游戏中没有其他汽车(如赛道狂飙),这使得代码简单,只需检查的与关卡中物体的碰撞。游戏的基本版只有一个主菜单,三个简单的单人赛道和每个赛道的排行榜(显示完成的时间)。

更多的图形设置(雪,沙漠,草原等等),更多的赛道,改编版本或多人游戏代码会在以后制作(例如在XNA社区)。

由于开发时间短,所以只保留了最基本的构思:控制汽车通过赛道。一个简单的物理系统被实现,每帧检测与场景中的静止物体的碰撞。其他构思在基本游戏中被放弃。这不仅简化了游戏,但简化了对技术和代码的理解。

这个游戏是从后面看,在前面显示汽车,赛道在中间,一些物品和天空在远处。天空是由一个天空立方体贴图实现的。

接下来是开发时间,所有的功能,哪个项目文件被使用,shader如何工作,音效如何使用。当讨论到使用的技术时会变得更有趣一点。

微软公司的赛车游戏初学者工具包使用C#和XNA Game Studio Express开发。使用XNA? API和托管代码有助于编写和阅读代码、执行如载入纹理、使用shader、只用一行代码显示模型等强大的功能。

图形都是.DDS格式的文件。所有模型(汽车,树木,Effects等等)都在3D Studio Max8中建模并导出为.x文件。模型不使用动画,这样更容易理解代码(注:我后来发现XNA不支持动画模型)。

这个游戏不使用任何现有的引擎或其他复杂的框架,这样做的话那些非游戏程序员会不熟悉它,只会使想要看源代码的人困扰。游戏由以下几个基本部分组成:

  • Helper类处理纹理加载,模型加载,游戏屏幕处理,XNA管理,处理控制等。

  • Shader类处理渲染模型(主要是汽车)和带有shader效果的场景。(注:我很快发现我低估了场景物体的数量)

  • Pre和post-screen shader类处理渲染天空和增加光晕效果、运动模糊和色彩校正。

  • 主菜单类处理开始游戏,检查排行榜和退出游戏。

  • 排行榜屏幕显示排行榜,并提交给一个在线服务器。排行榜还保存在本机上,也可通过这个类查看。(注:由于XNA不支持网络,而我想为PC和Xbox 360使用相同的代码,所以我放弃了将排行榜发送到在线服务器。)
  • 在Mission类中玩游戏。

这几乎就是所有的游戏构思了,当得到第一个XNA beta版本后我立即开始了编程。当然开发过程中还有许多问题,但借助于单元测试和游戏构思的不断更新,开发并不难。最难的部分是场景和赛道(见第12章)和第13章的物理系统。阴影映射对大多数没有经验的编程这也不是一件容易的事,但几个月后我在另一个引擎中实现了阴影映射,回过头来看未完成的赛车游戏,我确信没有阴影映射它不会很好看。

附加功能

如果你看以下整个赛车游戏的类视图(见图14-5),它看起来相当复杂。最大的帮助是Rocket Commander的项目,在它的单元测试和代码帮助下,我能很快地测试自己的想法,模型和渲染技术。后来当XNA引擎完成后,我就可以复制代码,并在新引擎中继续测试。例如,我很早就发现从二维图像产生赛道并不聪明,造成的问题比解决的更多。实现基本赛道不难,但当需要处理三维顶点是,我很高兴Rocket Commander游戏中有一些托管代码让我可以加载.x文件并使用它们的顶点生成赛道。但是XNA不支持访问或加载导入的3D模型的顶点,你可以编写自己的内容导入器,但要做太多的工作。后来我改变了赛道的导入方式并添加了许多功能(隧道,道路宽度,道路物体、棕榈树等)。在3D Studio Max中赛道被直接导出为Collada格式,然后以二进制格式(更快地装载)导入到游戏引擎中。

4
图 14-5

以下的功能是从以前的项目(主要来自于Rocket Commander)中导入的:

  • Helper类,如Log类处理调试,StringHelper类或其他如RandomHelper,Vector3Helper,或ColorHelper类等重要的类。

  • 该图形引擎是从头写起的,但通过扩展XNA类的功能,使用新的类处理纹理,材质,模型,字体的基本思路是来自与Rocket Commander。XNA中的大多数类简单得多,一开始做得并不多,比如说Model类,只加载了一个模型并通过几行代码显示它。但后来的模型渲染性能提高了很多(将在本章后面讨论),Model类的内在逻辑完全改变了。模型已不再直接被渲染,取而代之,每个三维模型的shader和网格被收集并在每帧末所用使用相同shader、材质、网格数据的网格被集中渲染。通过这种方式在Xbox 360游戏机上能使性能提高200% -300%。借助于特殊模型类的抽象,使用模型的代码也无需改变,它会变得更快!

  • 游戏屏幕逻辑100%地来自Rocket Commander。我很喜欢这个主意,而且实现起来很简单。

  • shader和其他图形类如ParallaxMapping,PostScreenGlow,PreScreenSkyCubeMapping和LensFlare类也是从Rocket Commander导入的,但经过一段时间后只有LensFlare和Sky Shader被留了下来,因为其他shader改变得太多了。无需为每一个新的材质编写一个新的shader,作为替代,编写一个更一般的ShaderEffect类,现在所有shader都是从这个类继承的。这简化了一些shader,并使像NormalMapping或ParallaxMapping变得过时了,因为它们现在直接工作自ShaderEffect类,而ShaderEffect类可以处理所有shader参数。PostScreenGlow shader继承自PostScreenMenu,这个新的shader仅用于菜单。
  • 对于单元测试也采取了类似的做法,但NUnit和TestDriven.NET都被排除在外以简化Xbox 360的开发,因为TestDriven.NET在Visual Studio的Express版本不能工作。

当然这个游戏也有一些新的功能,不光是阴影映射,还使用了以下几个类:

  • RenderToTexture:这个类服务于post-screen shader,但需要进行改进以支持阴影映射,这要求有不同的表面形式以获得更好的精度。这意味着,对普通的渲染目标你只能使用与后备缓冲相同的格式。这最有可能是R8G8B8X8,这意味着每个颜色通道使用8位而有8位是保留的,因为alpha通道对后备缓冲是无意义的,但32位优于24位,这使得在32位平台上更难读取像素数据。

    总之,阴影映射需要每像素更多的精度而不是很需要颜色。阴影映射的每个像素的深度值必须介于0和1之间 ,并越精确越好。良好的格式是R32F,如果R32F无法使用则R16F也可。但是,这些格式都必须进行不同的初始化,而RenderToTexture会为你处理。它也会根据用户的选择决定阴影映射大小是2048×2048,1024×1024或在速度较慢的电脑上只使用512×512。如果R32F和R16F都不能使用,它也支持回退到32位颜色格式。

  • ShadowMapBlur:这个类可以帮助您模糊阴影映射。所使用的技术类似于PostScreenGlowshader的发光技术。它通过两个步骤获取输入数据并模糊。模糊不仅使阴影更柔和更真实,也修正某些阴影映射错误,这些错误被模糊掉了。

    这种技巧在XNA Shooter中不使用,因为如果在背景上有很多小物体和很多阴影重叠区和非阴影区,看起来不太好。在赛车游戏看上去好得多,特别是汽车上的阴影有一些错误变得更加光滑。其他场景物体大多相距遥远,它们的阴影不会和其他物体重叠,这可以让你使用更好的模糊值。

  • ShadowMapShader:这是阴影的主要类。它初始化所有渲染目标,使用的纹理,阴影映射shadr,它处理ShadowMapBlur类。关于阴影映射技术的更多内容将在本章后面讨论后。

其他的游戏功能,比如环形赛道和场景渲染引擎已在第12章讨论过。它们包含在TrackLine类和Track类早期单元测试中,使游戏更有趣。

我真的不记得为什么游戏构思没有提及游戏屏幕。好像只说过:主菜单允许开始任务,查看排行榜,并退出游戏。代码后部是一个非常复杂的game screen命名空间(见图14-5),它比原计划支持更多的游戏屏幕。请注意,本章中某些游戏屏幕没有在代码中实现(例如,赛道或汽车选择屏幕),他们只用在XNA框架的赛车游戏初学者工具包中。最主要的原因是这里你只有一个赛道和一辆汽车,如果没有什么可以选择,那么实现它们是毫无意义的。你可以在http://www.xnaracinggame.com,这个游戏的官方网站找到一个更复杂的版本,并获取更详细的信息。