Skip to content

Latest commit

 

History

History
145 lines (80 loc) · 13.6 KB

01-Introduction.md

File metadata and controls

145 lines (80 loc) · 13.6 KB

序言

在五年级的时候,我和我的小伙伴们获准使用一个容放着一些非常破旧的 TRS-80s1的闲置教室。为了激励我们,一位老师找到了一份有一些简单的 BASIC 程序的打印文档给我们鼓捣玩耍。

电脑上的音频磁带驱动器是坏掉的,所以每次我们想要运行一些代码的时候,我们不得不仔细的从头开始键入。这使得我们更喜欢那些只有几行代码的程序:

10 PRINT "BOBBY IS RADICAL!!!"
20 GOTO 10

注解

如果计算机打印足够多的次数,或许它会神奇的变成现实哦。(译者注:这里指的是计算机反复打印第10行代码的语句BOBBY IS RADICAL!!!,作者开玩笑的说会变成现实。)

即便如此,整个过程还是充满了艰辛。我们不懂得如何去编程,所以一个小的语法错误便让我们感到很费解。程序出毛病是家常便饭,那时 我们只能重头再来。

在这些文档的最后部分,是一个真正的“怪物”:一个代码密密麻麻占去好几页纸的程序。我们光是鼓起勇气去尝试它就花了不少时间,不过它极为诱人——它的标题写着“隧道与巨魔”。我们不知道它是做什么的,不过它听起来像是个游戏,还有什么东西能比亲手写的一款电脑游戏更酷呢?

我们从没让它实际运行起来过。一年后,我们搬出了那个教室。(后来当我了解了一点 BASIC 时,才意识到它只是一个为桌面游戏使用的角色生成器,而并非整个游戏。)但木已成舟,从那之后,我立志要成为一个游戏程序员。

在我十几岁时,我的家人搞了一台装有 QuickBASIC 的 Macintosh,之后又装了 THINK C。我几乎整个暑假都在那上面倒腾游戏。自学是缓慢而且痛苦的。我能轻松的让一些东西运行起来——也许是一张地图屏幕或者一个小的猜谜游戏——但随着程序增大,编码变得越来越难。

注解

我的许多夏天都是在路易斯安那州南部的沼泽中捕蛇和乌龟来渡过的。如果户外不是这样酷热,很有可能,这将是一本爬虫学的书,而不是编程书。

起初,我的挑战在于让程序跑起来。后来,我开始琢磨如何编写比我脑袋所能想的更大的程序。 与其只是读一些关于“如何用C++编程”的书籍,我开始试图寻找一些关于如何组织程序的书籍。

匆匆过去几年后,一个朋友给了我一本书:《设计模式:可复用面向对象软件的基础》。终于来了!这就是我从青少年开始便一直寻找的那本书!我坐着把书从头到尾读了一遍。我之前仍然在我的程序里挣扎,但是看到别人也如此挣扎并提出了解决方案,我得到了救赎。我感觉我终于有了一些可以使用的工具,而不再是赤手空拳了。

注解

这是我和他第一次见面,在5分钟自我介绍之后,我坐在他的沙发上,并在接下来的几个小时里,我聚精会神地阅读而完全忽视了他。我感觉从那以后自己的社交能力还是至少有那么一丁点提升的。

在2001年,我得到了我梦想中的工作:EA(Electronic Arts) 的软件工程师。我迫不及待的想看下真正的游戏,以及工程师是如何组织它们的。像 Madden Football 这样的大型游戏到底是一个什么样的架构?不同系统之间是怎么交互的?他们是怎么让一套代码库在不同平台上运行的?

分解阅读源码是一个震撼人心和令人惊奇的体验。图形、人工智能、动画和视觉效果的代码都十分出众。我们公司有人懂得如何榨取CPU的每一个周期并得以善用。一些我不知道可行的东西,这些家伙午饭前就能搞定。

但是这些优秀代码构建的架构往往是事后想出来的。他们太专注于功能以至于忽视了组织架构。模块之间的耦合很普遍。新的功能通常粗糙的拴在代码之中,无论那里是不是能良好的嵌入。我的幻想破灭了,在我看来,恐怕很多程序员,如果他们曾经看过设计模式的话,就只学过单件而已。

当然,也不是真的那么糟糕。我曾设想游戏程序员们坐在放满白板的象牙塔中,连续几周地平静地讨论代码架构的细节。实际情况是,我眼前这份代码是别人在紧张的期限里赶工出来的。他们尽了自己最大的努力,同时,我逐渐认识到,他们竭尽全力的结果通常是十分优秀的。我写游戏代码的时间越长,就越能发现隐藏在这些代码之下的可贵之处。

不幸的是,“隐藏”一词往往是一个好的说明。宝藏埋在代码深处,而许多人正在它们之上路过。我看到过同事努力想改造出一个好的解决方案,那时,正是他们所需要的示例代码正藏在他们脚下的代码库之中。

这个问题正是这本书所关注的。我挖掘并打磨出自己在游戏中所发现的最好的设计模式,在此一一呈现给大家,以便我们将时间节省下来创造新事物,而不是重新造轮子。

市面上的书籍

目前市面已经有数十多本游戏编程的书籍。为什么还要再写一本?

我见过的大多数游戏编程书籍无非下列两类:

  • 关于特定领域的书籍。这些针对性较强的书籍让你深入地探索游戏开发的一些特定方面。它们会教你3D图形,实时渲染,物理模拟,人工智能,或音频处理。这些是众多游戏程序员在自己的职业生涯中所专注的领域。

  • 关于整个游戏引擎的书籍。相反,这些书尝试涵盖整个游戏引擎的各个部分。它们的目标是构建一整套适合某个特殊游戏类型的引擎系统, 通常是3D第一人称射击游戏。

我喜欢这两类书,但我觉得它们仍留有一些空白。特定领域的书很少会写你的代码块如何与游戏的其他部分交互。你可能擅长物理和渲染,但是你知道如何优雅的将它们拼合起来吗?

第二类书籍包含了这些,但我通常发现这类书都太过庞大,太过空泛。特别是随着移动和休闲游戏的兴起,我们正处在创作着大量不同类型游戏的时代。我们不再只是克隆 Quake2了。当你的游戏不适合这个模型时,这类阐述单个引擎的书籍就不再合适了。

相反,这里我想要做的,更倾向于分类讲解。本书的每个章节都是一个独立的想法,你可以将它应用到你的代码里。藉此,你可以用最合适的方式应用或者混用在你制作的游戏中。

注解

这种分类讲解风格的另外一个例子,就是广受大家喜爱的《游戏编程精粹》系列。

它和设计模式有什么联系

任何名字中带有“模式”的编程书籍都和经典图书《设计模式:可复用面向对象软件的基础》有所联系。这本书由 Erich Gamma,Richard Helm,Ralph Johnson 和 John Vlissides 完成。(俗称“Gang of Four”--四人组)

注解

设计模式一书本身也源自前人的灵感。使用模式语言来描述开放式解决问题的想法来自《A Pattern Language》,由 Christopher Alexander(以及Sarah Ishikawa,Murray Silverstein)完成。

他们的书是关于架构的(就像真正的建筑结构中建筑和墙壁和材料之间的关系),但他们希望他人会使用相同的结构来描述在其他领域中的解决方案。设计模式(Design Patterns)是 Gang of Four 在软件领域的一个尝试。

本书以“游戏编程模式”命名,并不是说 Gang of Four 的书不适用于游戏。恰恰相反,在[再探设计模式](02-Design Patterns Revisited.md)一节中覆盖众多来自GoF著作的设计模式,同时强调了在游戏开发中的运用。

从另一面说,我觉得这本书也适用于非游戏软件。我也可以把这本书命名为 More Design Patterns,但我认为游戏开发有更多迷人的例子。难道你真的想要阅读的另外一本关于员工记录和银行账户例子的书么?

也就是说,尽管这里介绍的模式在其他软件中也是有用的,但我觉得它们特别适合游戏中经常碰见的工程挑战:

  • 时间和顺序 往往是一个游戏的架构的核心部分。事情必须依照正确的顺序和正确的时间发生。

  • 开发周期被高度压缩,程序员们需要能够快速构建和迭代一组丰富且相异的行为,同时不牵涉到他人或者弄乱代码库。

  • 所有这些行为被定义后,游戏便开始互动。怪物撕咬英雄,药水混合在一起,炸弹炸到敌人和朋友...诸如此类。这些交互必须很好地进行下去,同时代码库不能变为交织错乱的毛线球。

  • 最后,性能在游戏中是很重要的。游戏开发者们总在不断比赛着看谁能够充分利用平台的性能。节省CPU周期的技巧,可能意味着A级游戏和百万销售与游戏掉帧和愤怒评论之间的不同。

如何阅读本书

_游戏编程模式_分为三大部分。第一部分是介绍和框架。这正是你现在阅读的章节以及[下一章节](01.1-Architecture, Performance, and Games.md)。

第二部分,再探设计模式,回顾了 Gang of Four 中的一些设计模式。在每个章节中,我会给出自己对该模式的认识,以及我如何认为它与游戏开发相关联。

最后部分是这本书的重头戏。这部分呈现了我认为十分有用的13种设计模式。它们分为四类:序列模式,行为模式,解耦模式,优化模式。

这些模式使用一致的文本组织结构来讲述,以便你将该书作为参考并能快速找到你所需要的内容:

  • 目的 部分用该模式想要解决的问题简单描述了该模式。它是第一个,这样你很容易根据自己遇到的问题来快速确定该用哪个模式。

  • 动机 部分描述了一个可引用该模式的示例问题。不同于具体的算法,模式通常是无形的,直到将它应用到某个具体的问题中。教模式而不举具体例子,就像教烤面包而不提面团一样。这个部分提供“面团”,之后的部分将会教你如何“烘培”。

  • 模式 部分会提炼出前面示例中的模式本质。如果你想了解该模式枯燥的书面描述,就是这部分了。如果你已经熟悉了该模式,这部分也是一个很好的复习,确保你没有忘记该模式的要素。

  • 到目前为止,该模式只是就一个单一的例子来解释的。但你怎么知道该模式是否适用于你的问题呢?使用情境 对模式使用的情境以及何时避免使用它提供了一些指导。使用须知 部分会指出使用该模式时面临的后果和风险。

  • 如果像我一样,需要借助具体的实例才能真正的理解,那么__示例__ 正满足你的需要。它一步一步的展示这个模式的完整实现,以便你可以看到模式究竟是如何工作的。

  • 模式和单一的算法不同,因为模式是开放式的。每次使用模式的时候,你实现的方式有可能会有不同。接下来__设计决策__ 部分,会探讨这个问题,并告诉你在应用模式时可供考虑的不同选项。

  • 为了圆满结束,这里一个短小的__参考__ 部分,它会告诉你该模式和其他模式的关联并指出使用该模式的一些真实的开源代码。

关于示例代码

这本书中的示例代码用 C++ 编写,但是这并不意味着这些模式仅在该语言中有用或者说 C++ 比其他语言要好。几乎所有的语言都适用,虽然有些模式确实倾向于有对象和类的语言。

我选择 C++ 有几个原因。首先,它是商业游戏中最流行的语言,是该行业的通用语言。 另外,C++ 所基于的 C 的语法也是 Java,C#,JavaScript和许多其他语言的基础。即使你不懂 C++,也没有关系,你可以很轻松的明白示例代码的含义。

这本书的目的不是教你学习 C++。示例会尽可能保持简单,但是这并不代表良好的 C++ 编码风格或使用。阅读代码时要理解代码所传达的思想,而不是代码本身的表达。

特别一提的是,示例代码没有采用“现代” C++ -- C++11 或更高版本风格。它没使用标准库并很少使用模板。这是“糟糕”的 C++ 代码,但我仍希望保留下来,这样会对那些从C,Objective-C,Java和其他语言转来的人们更加的友好。

为了避免浪费页面空间,你已经看过的或者和模式不相关的代码,有时会在例子中省略,通常用省略号来表示省去的代码。

比如有一个函数,它会处理一些工作,并且会返回一个值。讲解的模式是只关心返回值,不关心处理的工作。在这种情况下,示例代码看起来像这样:

bool update()
{
  // Do work...
  return isDone();
}

新的启程

模式是软件开发中一个不断变化和扩展的部分。这本书继续了 Gang of Four 的文献开启的过程,并分享他们了解的软件设计模式,这个过程,在本书写完之后还会继续下去。

你是这个过程的核心部分。只要你开发了你自己的模式和提炼(或者反驳!)这本书中提到的模式,你就是在为软件社区贡献力量。如果你有关于书中内容的任何建议,修正或者其他反馈,请与我联系。

============================

Footnotes

  1. 译者注:见维基百科TRS-80s

  2. 译者注:雷神之锤,第一个真3D实时演算的FPS游戏