下载本文的PDF版本 PDF

游戏开发:难于所想
JONATHAN BLOW,游戏开发顾问

十年前或二十年前,一切都充满乐趣。现在却是血汗和代码。

制作游戏最难的部分一直是工程。过去,游戏工程主要关注底层优化——编写在目标计算机上快速运行的代码,尽可能利用巧妙的小技巧。

但在过去的十年里,游戏的复杂性急剧膨胀。现在,主要的技术挑战仅仅是让代码能够工作,产生一个与预期功能有些相似的最终结果。在优化的程度上,我们通常关注的是高层算法的选择。有如此多种类的算法需要了解,如此多的经验需要以有用的方式来实现它们,以及如此多的工作总体上需要完成,以至于我们行业中一直存在合格人员的短缺。

今天制作游戏与甚至在1994年制作游戏是截然不同的体验。当然,它更困难了。为了讨论具体细节,我将困难分为两类:由整体项目规模和复杂性引起的问题,以及由高度领域特定要求引起的问题。虽然这将有助于我分阶段介绍情况,但这两种类别之间的区别有些人为;我们将在最后回到原点,看到存在根本的领域特定原因(由高度领域特定要求引起的问题),解释了为什么我们应该预期游戏是我们应该期望看到的最复杂的软件类型之一(由整体项目规模引起的问题),以及为什么我们不应该期望这种情况在可预见的未来发生改变。

项目规模和复杂性

为了说明过去十年游戏的增长,我选择了四个游戏示例并绘制了它们的图表。图表中的每个节点代表一个主要的功能领域,弧线代表模块之间的知识耦合。两个节点之间有弧线,它们需要大量通信,因此在一个节点中做出的设计决策将通过其邻居传播。

图1描绘了20世纪90年代早期的2D游戏,可能是一款家用游戏机的横向卷轴动作游戏,例如《超级银河战士》。其他类型的游戏会有稍微不同的图表,例如,像《文明》这样的回合制策略游戏会增加一个用于计算机对手AI(人工智能)的节点,但会失去快速图形的节点。当然,《超级银河战士》本身也有计算机对手,但它们的行为非常简单,不需要额外的节点;相反,敌人控制代码被归入“主要/杂项”。

到1996年,3D游戏已成为游戏产业产出的很大一部分。图2展示了一个早期的3D游戏,例如《机甲战士2》。将其与图3进行对比,图3是一个现代单人游戏。

我们目前尝试的最大努力是3D大型多人在线游戏(MMG),如图4所示。《无尽的任务》是3D MMG的典型首例,尽管更现代的例子将是《黑客帝国在线》(预计于2004年发布)。

将图4与图1进行对比,应该让您对情况的变化有一个大致的了解。这些图中的弧线假设代码已被理想地分解,但由于情况永远不是这样,现实生活中的情况将更加混乱。请记住,这些图表中的每个节点本身都是一个由许多算法协同工作的复杂系统,并且每个节点代表大约六千到四万行的源代码。

还有另一类游戏,非大型多人在线客户端/服务器游戏,它倾向于一次容纳较少的玩家(可能50个),并且不维护持久的世界。其中一个的图表将介于图3和图4之间。

工具。 为了应对如此复杂性,拥有出色的开发工具会有所帮助。遗憾的是,我们没有出色的开发工具。

对于PC上的编程,我们使用像Microsoft Visual Studio这样的编译器开发环境,它基本上是围绕他们的C++编译器的包装器;现在大多数游戏主要用C++编写。显然,我们不是微软的目标市场。Visual Studio似乎主要面向Visual Basic和C#应用程序的开发者,并且在某种程度上迎合C++,它是为大量使用COM对象并创建具有各种UI元素的许多窗口的应用程序而设计的。我们在现代游戏中很少做这些事情。我们更希望将人力投入到使系统快速编译程序,或生成高效的代码,或为使用C++模板的代码生成合理的错误消息。即便如此,Visual C++是我们PC上拥有的最好的编译器——没有竞争对手——所以我们只是随波逐流。

在游戏机上,游戏机制造商以及一两家第三方公司将提供一些开发工具(编译器、调试器、性能分析器等)。然而,游戏机生命周期大约为五年,并且工具制造商没有太多动力在周期结束时改进他们的产品。通常,游戏机开发者将使用一个只有一到四年成熟度的环境——这不是一个令人羡慕的情况。

为了构建像3D网格和动画这样的游戏内容,我们使用像Maya或3D Studio MAX这样的程序。然而,这些程序最初是为制作非实时动画(如故事片图形渲染)的人员创建的,因此它们不太适合。最近,随着游戏成为更大的业务,这些工具的制造商开始更多地关注我们,以至于他们将“游戏”放在其产品相关性列表的顶部。但是这些工具深深扎根于“错误领域”,并且如此庞大且难以改变,以至于它们仍然与我们真正需要的非常不同。例如,大多数游戏工作室将受益于构建大型连续3D世界网格的能力,允许多个艺术家同时处理同一个网格——或者编辑三角形网格以确保裂缝和孔洞不会出现的方法。这对我们来说比这些供应商开发和吹嘘的许多功能更有趣,例如复杂的布料模拟(仅对我们用于预渲染的电影过场动画有用,而电影过场动画在游戏中正变得越来越罕见)。

因此,我们需要用我们自己的插件和后处理工具来增强这些内容包,这些插件和后处理工具通常集成不良且功能匮乏,并且可能存在稳健性问题。有时,为了构建世界的几何形状,我们只是从头开始编写我们自己的领域特定编辑器(Worldcraft和UnrealEd就是这样的例子)。

从历史上看,资产管理工具的情况也很糟糕。现代游戏工作室需要一个快速而健壮的系统,用于对源代码、3D模型、动画、声音效果以及游戏中涉及的所有其他各种数据文件进行网络化的版本控制。最近,一些公司崛起,专门为游戏项目提供资产控制。这些工具仍然远非理想,但我们有理由希望它们会改进。

工作流程。 我们还有许多工作流程问题,这些问题并非直接与特定的工具软件相关。在编程方面,我们的编译/编辑/调试周期通常太长。许多游戏从头开始编译,或者当主要的C++头文件发生更改时,需要半小时或更长时间才能编译。即使是较小的更改,导致最少量的重新编译和重新链接,也可能需要长达两分钟的时间。一般来说,C++似乎鼓励长时间的构建。一旦构建时间变得太长,团队最终可能会投入大量工作来重构他们的源代码,以使其构建速度更快。通常这种情况发生得太晚,因为文件依赖关系变得如此混乱,以至于完全重构它就像从头开始重组项目一样。事实上,避免长时间构建的最佳方法是架构整个代码库以最大限度地减少依赖关系(有时会牺牲运行时效率!)。这种情况并不经常发生,因为许多工作室并没有像他们应该的那样认真对待这些工作流程问题,因为问题的影响在某种程度上是无形的,并且总是有许多明确而当前的问题需要处理——或者他们没有足够的纪律来处理这种微妙的问题,时间以年来衡量。

解决构建问题的另一种方法是使用第三方工具在多台机器上分发编译(其中一种产品是Incredibuild)。这些工具可以显著帮助,但它们不是万能的解决方案。

一旦游戏编译完成,我们必须运行它并测试我们的更改。然而,启动时间可能非常长,因为游戏通常需要加载大量数据。对于尚未完成加载时间优化的具有大型数据文件的调试版本,启动时间通常可能为三分钟。将此添加到编译和链接时间,您可以在进行最小可能的代码更改和看到新版本的游戏运行之间轻松地有五分钟的延迟。测试实际更改将需要更长的时间,因为程序员需要在游戏世界中设置适当的条件来执行该代码路径。

Visual C++提供了一个“编辑并继续”功能,其中可以将代码更改拼接到一个正在运行的程序中,从而避免这些延迟。然而,此功能的工作可靠性不足以消除问题(尽管当它确实有效时,非常受欢迎)。此功能通常不存在于游戏机系统的编译器环境中。避免这种周转时间的另一种方法是用更高级的扩展语言编写大量代码,该语言可以由游戏引擎动态重新加载而无需重新启动。(有关此方面的更多信息,请参阅Andrew M. Phelps和David M. Parks在本期第46页的“使用多语言开发的乐趣和游戏”)。

对于团队的内容开发部分,关于查看更改纹理或模型的效果需要多长时间,存在类似的问题。幸运的是,这个问题更容易解决;由于加载这些资源完全由我们的游戏引擎处理,我们有权解决这种情况。目前,一些经验丰富的开发者编写的游戏引擎提供了在运行时自动重新加载内容资源的功能,这正成为一种更普遍的趋势。

Jamie Fristrom1,2 最近为Gamasutra3撰写了一些专栏,从管理者的角度描述了这些工作流程问题。

多平台开发。 许多游戏被开发为在多个系统上运行。在开发过程中,我们经常需要在将更改提交到源代码控制之前,为所有构建类型(Debug,Release)和所有目标平台(PC,Playstation 2,Xbox)构建游戏。每当没有这样做时,墨菲定律几乎可以保证头文件或系统行为中的微小差异会导致编译时或运行时错误,从而扰乱编程团队其余成员的工作——这是一个糟糕的情况。因此,在程序员可以检入一批更改之前,他们可能需要执行两到五个完整的重新编译(正如我们前面提到的,有时每次需要半小时!)。程序员很容易等待数小时,因此有强烈的动机尽可能少地检入代码更改。但是他们不能等待太久,否则代码会与官方版本偏移太远,在合并时会引起麻烦。

与大型商业项目一样,较大的游戏团队往往有一个“构建主管”,其工作是监督构建,确保尽快纠正中断。有时,取悦构建主管可能是一项艰巨的任务。然而,尽管有构建主管的存在,构建似乎仍然经常被破坏。

所有这一切的结果是,游戏程序员经常无法只是坐下来完成工作;有重要的障碍需要克服。

第三方组件。 在图3和图4中有很多节点(请参阅我在本文下面对高度领域特定要求的讨论)。我们应该能够利用第三方产品来处理其中一些框,以减少我们的工作量。对于其中一些节点,存在可许可的第三方模块。然而,根据任务的性质,其中一些产品在满足行业需求方面比其他产品更成功。可用的产品涵盖以下领域:音频,底层(产品非常成功);渲染,底层(非常成功);渲染,场景管理(成功与否参半);碰撞检测和物理(仅在某种程度上成功,但自己编写这些系统非常困难,因此第三方工具在这里有显著的优势);网络,底层(略有成功,可以更好,但没有人推出合适的产品);骨骼动画和变形目标(非常成功);持久对象存储(成功与否参半);以及脚本语言(成功与否参半)。最值得注意的是,没有有用的AI功能产品存在,尽管有一些误入歧途的尝试。

由于游戏很复杂并且需要深入的技术知识(再次,请参阅我在下面对高度领域特定要求的讨论),仅仅使用这些第三方组件可能就很困难;通常,程序员必须在问题领域拥有丰富的经验,才能理解如何成功地与产品接口。即使是这种情况,程序员仍然可能在将第三方模块与游戏的其余部分集成时面临巨大困难。

这些模块中的大多数本身在技术上都具有挑战性,因此它们往往不尽如人意。通常,API(应用程序编程接口)很难处理,因为它体现了一些概念模型,这些模型与您的游戏需要工作的方式不太匹配。在主游戏代码和第三方API之间通常需要厚的胶合层。用于渲染或物理的应用程序编程接口通常希望以非常特定的方式组织数据,这种情况会传播到程序的其余部分并施加困难的约束(因为需要来回传递大量数据,我们不能只是在函数调用时在格式之间转换数据,因为那样会太慢)。并且由于游戏是如此CPU密集型的,因此经常会发生第三方组件在某些输入场景中呈现出显著的性能瓶颈——程序员必须修复这些情况或绕过它们。

通常,当第三方代码失败时,是因为它解决的问题不够大;对于开发团队花费使代码成功的努力量,他们不妨从头开始编写模块——这当然是您不想在使用许可代码失败后才发现的事情。许可第三方代码的决定应该始终以仔细的成本/效益分析为前提,因为不能保证该产品实际上会加快您的开发速度。

全功能引擎选项。 除了许可组件,我们可以从一家成功构建了可靠引擎的公司许可整个游戏引擎(请参阅我在本文中对高度领域特定要求的讨论)。构建可许可的引擎比仅仅制作游戏更困难,因此没有太多可以合理选择的引擎。最近的一些例子是Quake 3引擎和Unreal引擎。这种许可的成本往往很高,每个零售SKU(库存单位)可能为30万到60万美元。如果您试图制作一个在技术上没有做任何新事物的游戏,这样的许可可能是一个安全的决定。但是,如果您试图在技术上进行扩展,您可能会遇到前面提到的不匹配问题,但这次规模更大——您可能会发现自己花费了50万美元购买最终大部分被重写、禁用或绕过的代码。(即便如此,这笔钱也可能是物有所值的,因为拥有引擎为您提供了一个启动,有时比从零开始更好。)

上述两个引擎都来自第一人称射击游戏(FPS)类型,这是最精湛的游戏技术蓬勃发展的领域。对于与FPS非常不同的游戏,您可能很难找到可用的引擎。没有市场验证的MMG引擎。

我已经讨论了导致当今游戏开发困难的许多与工具相关的问题。这些问题变化缓慢。有了更好的工具和工作流程,我们将能够制作更好的游戏,提高我们可以处理的游戏复杂性和功能水平。然而,游戏实际上不会变得更容易制作,因为创建游戏的难度将始终扩展,直到超过我们的实现能力。下一节关于高度领域特定要求的挑战将讨论为什么会这样。

高度领域特定要求

目前,游戏中有三个级别的编程:脚本代码、游戏玩法代码和引擎代码。脚本和游戏玩法代码控制游戏的整体内容、规则和高级行为。在本文的其余部分中,我将把它们视为一个概念,并仅称为“游戏玩法代码”。位于游戏玩法代码下方的是引擎,它为模拟和I/O提供所有基本机制。引擎代码比游戏玩法代码更难编写,首先是因为它需要高级知识,而且还因为它必须保持更严格的质量和性能标准。

引擎代码。 当然,要编写好的引擎代码,您需要对软件工程有很好的掌握。而且,还需要大量的领域特定知识。这可以大致分为两类,数学知识和算法知识。

数学知识。 如果程序员没有对基本的线性代数4以及2D和3D几何的良好掌握,那么他就不可能胜任现代游戏。我们经常使用4D表示进行基本操作(用于一般线性变换的4D齐次坐标,以及用于表示旋转的四元数5),因此推理更高维度的能力非常有用。基本微积分对于各种模拟和渲染任务都是必要的。对于许多渲染任务,信号处理数学非常重要——线性信号处理6以及球谐函数的模糊研究7。对于任何类型的复杂模拟,您都需要数值分析和微分形式方面的经验。对于网络,信息论和压缩和密码学背后的统计数据对于构建健壮的系统是必要的。

算法知识。 优秀的引擎程序员应该非常熟悉许多算法——如此之多,以至于试图在此处列出它们是愚蠢的。最必要的算法执行诸如空间划分、聚类以及几何图元的相交和裁剪之类的任务。大多数算法将主要集中在一个任务领域,例如渲染或物理,但这些算法通常非常深入,需要一段时间才能掌握。多年来,我们一直在挖掘学术研究以寻找和修改合适的算法。然而,游戏引擎必须满足软实时要求,并且相关学科领域中的大多数学术工作都面向批量计算。(过去图形学的大多数研究都应用于离线电影渲染。大多数物理算法是不稳定的,可能会彻底失败,这在批量设置中可以通过调整初始条件并再次尝试来解决。这些算法不能成功地适应软实时设置。)随着游戏现在开始被学术界认真对待,这种情况开始发生变化,但大多数学术研究仍然指向对我们没有太大帮助的方向。因此,创建技术上雄心勃勃的游戏引擎通常需要大量的原创研究。

引擎程序员不一定需要深入了解上述所有数学和算法部门。但是,由于他们在如此紧密耦合的系统中工作,即使一个概念没有直接出现在他们正在处理的模块中,它也可能通过邻居传播而显着影响他们的工作。因此,引擎程序员将需要对大多数这些主题有轻度到中度的了解才能完成工作,并且应该足够适应以在需要时学习其他主题。

交叉关注点。 为了成功构建游戏引擎,仅仅理解大量的数学和算法是不够的。当您将许多算法组合到一个紧密耦合的系统中时,各种算法施加的约束将发生冲突。选择或发现可以组合成和谐整体的算法需要一定的经验和智慧。当游戏引擎失败时,通常是因为它们没有实现这种和谐。

图3和图4中的每个节点都代表一个充满交叉关注点的复杂系统。此外,许多这些节点代表了跨越系统概念空间大部分的切割。目前,我们没有编程范例可以帮助我们解决这个基本的结构性问题。(语言研究的一些新成果,如面向方面的编程,正在进入该领域,但它们目前都不适用于生产用途。)

模拟深度。 游戏代码本质上是关于模拟某种世界的。在早期的游戏中,模拟是简单而原始的。有一段时间,我们主要关注图形,这是对光在游戏世界中如何表现的模拟。但是现在我们正在进入一个时代,在这个时代,控制物理和AI的模拟部分对于最终用户的体验质量可能比图形更重要。由于通用AI是一个尚未解决的问题,因此没有人知道它在未来会是什么样子。但是,我们对物理学有一些了解。物理学方面的工作使我们了解了一些可以概括为与各种模拟时间演化复杂系统相关的问题。

模拟复杂系统通常涉及使用数值方法随时间积分数量。因此,在较低级别,必须以可积分的方式指定数量。包含任意不连续性的函数很难进行数值积分,但这些也是计算机默认创建的函数类型。(除非我们明确努力使其不这样做,否则If/then语句会创建不连续性;因此,在处理低级模拟时,我们必须小心If/then语句!)为了帮助保持事物的可积分性,包括AI决策在内的重大世界事件需要在高于基本积分器的级别发生;也就是说,它们不能在没有警告的情况下突然介入并改变世界状态。

一旦我们完成了所有这些,我们就需要担心刚度——仅仅通过调整常数,您就可以导致模拟变得不稳定。根据我们当前最好的方法,良好的积分技术只能在模拟空间内提供一个稳定性区域;您必须注意不要踏出该区域。

然后我们需要担心隧道效应,当我们在太长的时间步长上积分时会发生隧道效应,导致我们错过一个重要的世界事件。“隧道效应”一词来自碰撞检测,我们在其中基本上通过将实体在空间中短距离传送来移动实体;如果我们移动实体太快,它可能会穿过像墙壁这样的固体物体,除非我们采取额外的步骤来检测这种情况。这些额外的步骤构成了对“真正应该发生的事情”的近似,这可能会导致一致性问题。

有趣的模拟本质上涉及许多不同实体之间的微妙交互,这是一个n2问题,实际上不想在实时中解决。为了解决这个问题,我们需要擅长剔除可以忽略不计的交互,以缩小问题规模。但是这种剔除往往涉及黑色艺术启发式方法,并且可能会以奇怪而微妙的方式出错。

性能分析。 我们始终在努力尽可能地推动CPU,因此性能分析非常重要。不幸的是,没有好的游戏性能分析器。游戏根据动态条件表现出高度模态的行为(在某个时刻,将三角形发送到图形硬件可能是性能瓶颈;下一时刻,检测游戏实体之间的碰撞可能是问题所在)8。为了提高游戏性能,我们需要识别这些单独的行为模式。不幸的是,商业性能分析产品本质上是平均程序在一段时间内的活动,这会将所有这些峰值融合成模糊不清的糊状物,从而隐藏问题。

通常,我们在游戏中构建自己的简单性能分析系统。虽然有用,但这不像拥有成熟的性能分析工具。图形硬件供应商,如ATI和NVIDIA,制作了一些特定于图形的性能分析工具,一些游戏机制造商也是如此。这些工具也很有帮助,但通常不足以获得系统的鸟瞰图。

风险。 计算机游戏始终朝着增加技术复杂性的方向发展,以为玩家提供他们从未体验过的事物。因此,每一波游戏都在尝试几项神秘且未经证实的技术壮举。因此,游戏开发者承担了大量的技术风险(您无法准确安排未知事件或预测它将如何与系统的其余部分交互)以及游戏设计风险(最终用户会如何看待这种从未实现过的功能?我们为实现它所付出的所有努力是否值得?)。

结论

游戏很难。本文试图对原因进行广泛的总结;尽管为了保持解释的简洁,省略了许多相关因素。

制作游戏所涉及的挑战并非令人沮丧,而是许多聪明人被吸引到该领域的主要原因之一。新方法的不断发展,加上运行它们的速度更快的计算机,使这成为一个非常有趣的时代。

致谢

感谢Michael Abrash、Sean Barrett、Atman Binstock、Charles Bloom、Chris Butcher、Doug Church、Chris Green、Chris Hecker、Casey Muratori和Jay Stelly的投入。

参考文献

1. Fristrom, J. Manager in a Strange Land: Turnaround Time. Gamasutra (Nov. 28, 2003); http://www.gamasutra.com/features/20031128/fristrom_01.shtml (需要免费帐户和密码)。

2. Fristrom, J. Manager in a Strange Land: Content Turnaround. Gamasutra (Dec. 5, 2003); http://www.gamasutra.com/features/20031205/fristrom_01.shtml (需要免费帐户和密码)。

3. Gamasutra(面向游戏开发者的门户网站,需要免费帐户和密码):请参阅 http://www.gamasutra.com/

4. Sheldon, A. Linear Algebra Done Right, 第2版。施普林格出版社,纽约:纽约州,1997年。

5. Hamming, R.W. 数字滤波器。多佛出版社,花园城:纽约州,1998年。

6. Eberly, D. 四元数代数和微积分,1999年(2002年更新); http://www.magic-software.com/Documentation/Quaternions.pdf

7. Green, R. 球谐光照:粗略的细节。游戏开发者大会论文集(2003年1月16日),第1-47页; http://www.research.scea.com/gdc2003/spherical-harmonic-lighting.pdf

8. Blow, J. 交互式性能分析1-3。游戏开发者杂志(2002年12月-2003年2月)。

JONATHAN BLOW是一位游戏开发顾问,自1995年以来一直在行业工作。最近的项目包括《杀出重围2》和《微软模拟火车2》。Blow还为《游戏开发者》杂志撰写名为“内积”的月度专栏,专注于游戏开发中的前沿技术问题。

 

acmqueue

最初发表于Queue第1卷,第10期
数字图书馆评论本文





更多相关文章

Walker White, Christoph Koch, Johannes Gehrke, Alan Demers - 更好的脚本,更好的游戏
2007年,视频游戏产业收入达到88.5亿美元,几乎与电影票房收入相当。其中大部分收入来自大型团队创作的热门游戏。尽管大型开发团队在软件行业中并不少见,但游戏工作室往往拥有独特的开发者群体。软件工程师在游戏开发团队中占比较小,而团队的大部分由内容创作者组成,例如艺术家、音乐家和设计师。


Jim Waldo - 游戏与虚拟世界中的扩展
我曾经是一名系统程序员,从事银行、电信公司和其他工程师使用的基础设施工作。我从事操作系统工作。我从事分布式中间件工作。我从事编程语言工作。我编写工具。我做了硬核系统程序员所做的所有事情。


Mark Callow, Paul Beardow, David Brittain - 大型游戏,小型屏幕
在创建和分发移动3D游戏时,立即显而易见的一件事是,手机市场与更传统的游戏市场(例如游戏机和掌上游戏设备)之间存在根本差异。其中最引人注目的是交付平台的数量;设备的严重限制,包括方向可以更改的小屏幕;有限的输入控制;需要处理其他任务;非物理交付机制;以及手机性能和输入能力的变化。


Nick Porcino - 游戏图形:革命之路
从彩色精灵在平铺块背景上的日子到现代游戏中沉浸式3D环境,这是一段漫长的旅程。曾经是单个游戏创作者的工作,现在已成为涉及各个创意学科人员的多方面制作。下一代游戏机和家用电脑硬件将带来可用计算能力的革命性飞跃;每秒万亿次浮点运算或更多的运算能力将来自商品硬件。





© 保留所有权利。

© . All rights reserved.