Skip to content

Latest commit

 

History

History
171 lines (146 loc) · 13.1 KB

2017-07-28-GameProgrammingGems1.markdown

File metadata and controls

171 lines (146 loc) · 13.1 KB
layout title subtitle date author header-img
post
游戏编程精粹 第二卷阅读笔记
游戏是商品还是艺术品?
2017-07-27 15:00:00 -0700
tachen
img/post-GameProgrammingGems1-bg-00.png

第二卷:游戏商业时代


通用编程技术

> 阅读本章内容之前,请读者回答这样一个问题:何为工程师(或者说您从事的是什么样的工作)?工程师师编写代码 > 或能够使得大量三角形快速地绘制出来的人吗?当然不是。很多工程师并不编写大量代码。工程学研究的是如何解决问题。 > > 那么,在游戏开发工作室,工程师扮演的是什么角色呢?答案很简单:工程师为开发小组服务。撇开人们常常同时扮演多种 > 角色不谈,开发小组通常分为三个主要的小组。首先是设计人员,他们负责设计游戏的脉络,并确保其有趣;其次是内容开发人员 > ——通常是艺术家、作曲家和关卡设计师,他么负责制作设计方案所需的素材;最后是工程师,他们负责实现设计方案——所需的时间 > 通常要长得多。工程师负责创建一个系统,让玩家能够同游戏中的素材交互。换句话说,工程师通过创建工具,来为小组提供服务,服务? > 工具? > > 人们通常认为是工具的(如关卡编辑器或脚本批处理器)只是画面中可见的、突出的部分。工程师创建的所有东西都是工具,无论 > 是用于播放或混合艺术家创建的动画的引擎、用于管理交互式内容的游戏内嵌的数据库,还是跟踪内存使用情况的调试设施。我们 > 的终极目标是,创建出能够实现游戏设计方案的软件工具。 > > 我们创建的很多工具并没有嵌入到游戏中,它们用于创建和处理数据,以便高效地播放或模拟游戏引擎。这样的工具包括BSP编译器、纹理压缩程序、 > 资源组合器和关卡编辑器。这些工具通常只供开发人员和模型设计人员(mod maker)使用。没有它们,游戏也能运行;但对于创建游戏而言, > 它们是必不可少的。当前,这种工具开始被集成到游戏引擎中。这样做旨在加快游戏的开发进度,因为这使得游戏中很大一部分内容可以在游戏运行的 > 同时进行编辑。 > > 现代的游戏非常复杂,为高效地调试和优化它们,游戏本身必须提供大量的支持功能。由于机器中安装的内存有几十兆(不久后将为几百兆), > 因此游戏中包含的内容多得令人难以置信,为免遭灭顶之灾,我们必须创建复杂的支持系统。我们创建调试系统、性能分析程序、类型数据库、 > 、实用程序库、stack-dumping异常处理程序、记录工具、自检代码等,真是数不胜数。本章所介绍的正式这样的工具,这些文章将帮助读者 > 打下坚实的游戏开发基础。

现在手机上安装的内存:41%已经到1G,2G也有35%,将来手机系统支持64位,就能装更大的内存,想想当年在PC上也才几十兆

何时使用内联函数

> 为何不将所有的函数都作为内联函数呢?这可以消除整个程序的函数开销,从而使填充速度更快,响应时间更短吗?显然回答是否定的。 > 虽然通过消除函数调用开销以及允许执行过程简编译器优化、代码扩展可以提高速度,但这是以增加代码长度为代价的。度量程序的性能时, > 需要考虑两个因素:执行速度和代码的实际长度。代码长度增加将占用更多的宝贵内存,从而降低执行速度。随着程序的内存需求增加, > cache missing和缺页的可能性也将增大。cache missing将导致稍微的延迟,而缺页将导致很大的延迟,因为虚拟内存单元不再物理内存中, > 必须从硬盘中取回它。在400MHz的Pentium Ⅱ台式机上,一次硬缺页将导致大约10μs的延迟,这大约相当于4000 000个CPU周期 [Heller99]

对代码的优化深入到CPU指令层面

抽象接口编程

> 抽象接口的概念很简单,但功能非常强大。它让我们能够将接口完全同其实现分开,这带来了一些好处; > > ▪易于在代码的不同实现间切换,而不影响游戏的其他部分。当实验不同的算法或者不同的平台上修改实现时,这尤其有用。 > > ▪可在运行阶段修改实现。例如,如果图形渲染器是通过抽象接口实现的,则可以在游戏运行期间,在软件渲染器和硬件加速渲染器之前进行切换。 > > ▪对接口的用户完全隐藏了实现的细节。这样在整个工程中包含的头文件将更少,重新编译的速度将更快,因此当需要完全重新编译整个工程师,所需的时间将更短。 > > ▪即使在游戏被编译和发行之后,还可以很容易地将已有接口的新实现加入到游戏中。这样,可以通过提供更新或用户自定义的修改,轻松地对游戏进行扩展。

Game Framework的针对接口编程值得学习

使用操作系统特有的特性

> 显示装载DLL可以解决的另一个问题是,应用程序要使用一个特定的API函数(如果该函数可用的话)。有许多以“Ex”结尾的扩展函数, > 这些函数在Windows NT或Windows 2000中是支持的,但在Windows 95或Windows 98中不可用。这些函数通常比原来的函数提供的信息或功能更多。 > > LoadLibray和GetProcAddress可用于游戏DLL。一个这样的例子是Ensemble工作室正在开发的游戏引擎中的图形支持。在该游戏引擎中, > 对Direct3D和OpenGL的图形支持被放在不同的DLL中,必要时可以显示地装载这些DLL。如果需要Direct3D图形支持,则使用LoadLibrary装载 > 支持Direct3D的DLL,并使用GetProAddress找到导出的函数。这种设计使得可执行主文件无需隐式地链接d3d8.lib或opengl32.lib或opengl32

对操作系统的了解也是游戏程序员的必修课

一个游戏实体工厂

> 近年来,事实证明,对于游戏开发而言,脚本语言的价值是无法估量的,通过将修改游戏实体行为的代码从核心代码中分离出来,脚本语言使 > 关卡设计器(Level designer)能够脱离代码的编译执行循环,将游戏测试和调整的速度提高了几个数量级,并让高级程序员能够将时间用于完成更 > 复杂的任务。 > > 然而,为使数据驱动的开发模式得以顺利地进行,游戏引擎必须提供灵活的实体构造和组装服务,这样脚本语言才能为各个实体提供不同的作战策略、 > 反应行为和其他参数。本文旨在描述一个C++类层次和一套技术,以支持引擎方面的数据驱动开发模式: > > ▪将逻辑行为和音频视频行为分开。必要时,一个Door类能够支持这一概念的很多变体,而无需关心动画序列的大小和关键帧数目。 > > ▪快速开发。定义好基本行为库后,便可以在框架中添加新的游戏实体,这只需很少的代码,所需时间通常不超过15分钟。 > > ▪避免代码重复。通过在运行阶段将行为组装到新实体中,该框架避免了使用脚本语言时,代码过长(相对于C/C++)的问题。

组件式开发已集成在各大引擎中,Game Framework中也提供了一套实体方案

在C++添加摒弃功能

> 在软件的整个生命周期中,函数接口可能需要修改、废弃或完全替换为新的接口。对于哪些被重用于多个项目或已用了多年的库和引擎, > 尤其是这样的。当函数与项目其他部分之间的接口被修改后,游戏(或/和工具)可能无法通过编译。对于开发大型项目的小组而言, > 情况更糟,因为很多人可能会更频繁地修改接口。 > > 可能的解决方案:对于这种情况,处理的方式有多种: > > ▪无为而治。只要接口发生变化,继续工作之前所有的人都必须修改那些调用改动了的函数的代码。这对于一个人的团队而言是可行的, > 但对于大型团队而言,通常是不可接受的。 > ▪不修改接口函数。这通常是不可能的,尤其是在瞬息万变的游戏行业。可能硬件变了,可能发行商变了,可能发行商需要新的东西, > 也可能最初的接口有问题。采用这种方式弊大于利,将导致函数或类的名称名不副实。 > > ▪创建新的接口版本。这种方式坚持不修改接口,而是创建新的接口来解决所有的问题。项目中将包含新的接口和原来的接口。DirectX > 采用的就是这种方式。对于需要完全修改接口或不常更新接口的情况,这种方式管用;但对于经常需要更新或要做小的更新的情况,这种 > 方法不太好。另外,采用这种方式时,需要维护当前接口的整个实现以及大量的旧接口,而这可能是一场噩梦。 > > 显然,对于现代游戏开发,这些解决方案都不理想。我们必须采用其他方式来处理这种问题。 > > 理想的解决方案:我们真正希望的是,能够编写新的接口函数,并将旧的接口函数保留一段时间。这样,小组的其他成员可以立即开始使用 > 新函数。他们在有时间对原来的代码进行修改,使之使用新的函数,经过一段时间后,当没有任何人使用旧的函数时,便可以将其删除。 > > 这里的问题是,如何让每个人知道哪些函数已被修改以及它们被认为将使用哪些函数替代。即使我们总是将这种信息告诉他们,但如果一切 > 通过编译并正确运行,他们怎么会去记住这些呢?可以摒弃函数。编写新函数后,我们将函数标记为被摒弃的。这样,每当旧函数被使用时, > 编译器都将生成一条消息,指出调用的是一个被摒弃的函数,同时指出应使用哪个函数替换它。

如今Unity3d引擎的接口升级就是这样,但是当时C++语言并没有提供这个特性,需要自己扩展

游戏输入的记录和重放

> 18世纪的数学和物理学家Marquis Laplace指出,如果能够知道宇宙中每个例子的位置、方向和速度,将可以通过一个公式来详细预测未来和过去。 > 这就是决定论。 > > 混沌理论、海森堡的测不准原理和量子物理中的随机性表明,决定论是错误的。然而,在简化的游戏领域中,Laplace的决定论却是管用的。 > > 如果您仔细记录影响游戏的每一项内容,便可以重放记录,让昔日重现。 > > 记录输入有何用途:重现难得一见的bug、重放有趣的游戏、度量优化效果或创建游戏电影。

这个也可以用在网络同步上:第一步先实现游戏输入的记录和本地重放,下一步通过网络在远端重放,完成同步

一个灵活的文本分析系统

> 几乎每个现代游戏都需要某种文本分析程序。本文展示了一个功能强大、易于使用的文本分析系统,该系统可用于处理任何类型的文件格式。 > > 在表示数据方面,文本文件有很多优点: > > ▪它们易于使用任何标准文本编辑器进行读取和编辑。二进制数据通常要求创建、调试和维护定制的工具。 > > ▪它们灵活——可使用同一个分析程序进行简答的变量赋值或编写更复杂的脚本。 > > ▪它们可以在代码和数据之间共享常量。 > > 不幸的是,文本文件也有些缺点: > > ▪不同于大多数二进制格式,文本必须首先进行标记(tokenize)和解释,因此装载速度更慢。 > > ▪在空间方面,存储文本的效率不高,它浪费磁盘空间并降低文件装载速度。 > > 由于很多游戏参数是需在开发阶段进行调整,因此可以在开发阶段使用基于文本的格式,而在产品中使用更佳的二进制格式。 > 这样使融合了两方面的优点:文本数据易于使用;二进制数据的装载速度快。

现在我们使用自动化生成和按需加载策略

变化

从第二卷开始,增加了一个大类:音频处理

小结

学习别人解决问题的方案,继续往前走一点

题外话

第一、二卷中文版翻译的作者姚勇所创办的公司Hardcore3d因为资金问题没能继续开发下去,很感慨! 游戏是商品还是艺术品,要商业多一点还是游戏纯粹一点?技术与艺术的结合?各种冲突不断地在许多项目 中重复上演,这么多年过去了,对于我来说,现在想要自我调整一下:游戏性多一点,商业放在后面一点;技术多一点,游戏好一点;最终多积累一点,成功晚一点。

参考资料

Game Framework开源框架

Unity 游戏配置表格代码自动生成术

姚勇与大理辐射软件开发有限公司技术委托开发合同纠纷案