序
游戏设计模式
在五年级时,我和我的朋友被准许使用一间存放有几台非常破旧的 TRS-80s 的房间。 为了鼓舞我们,一位老师给我们找了一些简单的 BASIC 程序打印文档。
电脑的磁带驱动器已经坏掉了,所以每当我们想要运行代码,就得小心地从头开始输入代码。 因此,我们更喜欢那些只有几行长的程序:
10 PRINT "BOBBY IS RADICAL!!!" 20 GOTO 10
如果电脑打印的次数足够多,也许这句话就会魔法成真。
哪怕这样,过程也充满了困难。我们不知道如何编程,所以小小的语法错误对我们也是天险。 如果程序没有工作——这经常发生——我们就得从头再来一遍。
文档的最后几页是个真正的怪物:一个占据了几页篇幅的程序。 我们得花些时间才能鼓起勇气去试一试,但它实在太诱人——它的标题是“地道与巨魔”。 我们不知道它能做什么,但听起来像是个游戏,还有什么比自己编个电脑游戏更酷的吗?
我们从来没能让它运行起来,一年以后,我们离开了那间教室。 (很久以后,当我真的学会了点 BASIC,我意识到那只是个桌面游戏角色生成器,而不是游戏。) 但是命运的车轮已经开始转动——自那时起,我就想要成为一名游戏程序员。
青少年时,我家有了一台能运行 QuickBASIC 的 Macintosh,之后 THINK C 也能在其上运行。 几乎整个暑假我都在用它编游戏。 自学缓慢而痛苦。 我能轻松地编写并运行某些部分——地图或者小谜题——但随着程序代码量的增长,这越来越难。
暑假中的不少时间我花在路易斯安那州南部的沼泽里逮蛇和乌龟上了。 如果外面不是那么酷热,很有可能这是一本讲爬虫而不是编程的书了。
起初,挑战之处仅仅在于让程序成功运行。然后,是搞明白怎样写出内容超出我大脑容量的代码。 我不再只阅读关于“如何用 C++编程”的书籍,而开始尝试找那些讲如何 组织 程序的书。
几年过后,一位朋友给我一本书:《设计模式:可复用面向对象软件的基础》。 终于!正是我从青年时期就在寻找的书。 我一口气从头读到尾。虽然我仍然与自己的程序挣扎,但看到别人也在挣扎并提出了解决方案是一种解脱。 我意识到手无寸铁的我终于有件像样的 工具 了。
那是我首次见到这位朋友,相互介绍五分钟后,我坐在他的沙发上,接下来几个小时,无视他并全神贯注地阅读。 我想自那以后我的社交技能还是有所提高的。
在 2001 年,我获得了梦想中的工作:EA 的软件工程师。 我等不及要看看真正的游戏,还有专业人士是如何将组织一切的。 像实况足球这样的大型游戏使用了什么样的架构?不同的系统是如何交互的?一套代码库是如何在多个平台上运行的?
分析理解源代码是种震颤的体验。图形,AI,动画,视觉效果皆有杰出代码。 有专家知道如何榨干 CPU 的最后一个循环并好好使用。 那些我都不知道是否 可行 的事情,这些人在午饭前就能完成。
但是这些杰出代码依赖的 架构 通常是事后设计。 他们太注重 功能 而忽视了架构。耦合充斥在模块间。 新功能被塞到任何能塞进去的地方。 在梦想幻灭的我看来,这和其他程序员没什么不同, 如果他们阅读过《设计模式》,最多也就用用 单例 。
当然,没那么糟。我曾幻想游戏程序员坐在白板包围的象牙塔里,为架构冷静地讨论上几周。 而实际情况,我看到的代码是努力应对紧张截止期限的人赶工完成的。 他们已经竭尽全力,而且,就像我慢慢意识到的那样,他们的全力以赴的结果通常很好。 我花在游戏代码上的时间越多,我越能发现藏在表面下的天才之处。
不幸的是,“藏”是普遍现象。 宝石埋在代码中,但人们从未意识到它们的存在。 我看到同事重复寻找解决方案,而需要的示例代码就埋在他们所用的代码库中。
这个问题正是这本书要解决的。 我挖出了游戏代码库中能找到的设计模式,打磨然后在这里展示它们,这样可以节约时间用于在发明新事物上,而非 重新 发明它们。
书店里已有的书籍
书店里已经有很多游戏编程书籍了。为什么要再写一本呢?
我看到的很多编程书籍可以归为这两类:
特定领域的书籍。 这些关于细分领域的书籍带你深入理解游戏开发某一特定层面。 它们会教授你 3D 图形,实时渲染,物理模拟,人工智能,或者音频播放。 那些很多程序员穷其一生研究的细分领域。
完整引擎的书籍。 另一个方向,还有书籍试图包含游戏引擎的各个部分。 它们倾向于构建特定种类游戏的完整引擎,通常是 3D FPS 游戏。
这两种书我都喜欢,但我认为它们并未覆盖全部空间。 特定领域的书籍很少告诉你这些代码如何与游戏的其他部分打交道。 你擅长物理或者渲染,但是你知道怎么将两者优雅地组合吗?
第二类书包含这些,但是发现完整引擎的书籍通常过于整体,过于专注某类游戏了。 特别是,随着手游和休闲游戏的兴起,我们正处于众多游戏类型欣欣向荣的时刻。 我们不再只是复制 Quake 了。如果 你的 游戏与该类游戏不同,那些介绍单一引擎的书就不那么有用了。
相反,我在这里做的更 à la carte 。 每一章都是独立的,可应用到代码上的思路。 这样,你可以用 你 认为最好的方式组合这些思路,用到你的游戏上去。
另一个广泛使用这种 à la carte 风格的例子是 Game Programming Gems 系列。
和设计模式的关联
任何名字中有“模式”的编程书 都与 Erich Gamma,Richard Helm,Ralph Johnson,和 John Vlissides(通常被称为 GoF)合著的经典书籍: 《设计模式:可复用面向对象软件要素》相关。
《设计模式》也受到之前的书籍的启发。 创建一种模式语言来描述问题的开放式解法, 这思路来自 A Pattern Language , 作者是 Christopher Alexander (还有 Sarah Ishikawa 和 Murray Silverstein).
他们的书是关于架构的(建筑和墙那样的 真正的 框架结构), 但他们希望其他人能使用相同的方法描述其他领域的解决方案。 《设计模式》正是是 GoF 用这一方法在软件业做出的努力。
称这本书为“游戏编程模式”,我不是暗示 GoF 的模式不适用于游戏编程。 相反:本书 重返设计模式 一节包含了《设计模式》中的很多模式, 但强调了这些模式在游戏编程的特定使用。
同样的,我认为本书也适用于非游戏软件。 我可以依样画瓢称本书为《更多设计模式》,但是我认为举游戏编程为例子更为契合。 你真的想要另一本介绍员工记录和银行账户的书吗?
也就是说,虽然这里介绍的模式在其他软件上也很有用,但它们更合适于处理游戏中常见的工程挑战:
时间和顺序通常是游戏架构的核心部分。事物必须在正确的时间按正确的顺序发生。
高度压缩的开发周期,大量程序员需要能快速构建和迭代一系列不同的行为,同时保证不烦扰他人,也不污染代码库。
在定义所有的行为后,游戏开始互动。怪物攻击英雄,药物相互混合,炸弹炸飞敌人或者友军。 实现这些互动不能把代码库搞成一团乱麻。
最后,游戏中性能很重要。 游戏开发者处于一场榨干平台性能的竞赛中。 节约 CPU 循环的技巧区分了 A 级百万销量游戏和掉帧差评游戏。
如何阅读这本书
《游戏设计模式》分为三大块。 第一部分介绍并划分本书的框架。包含你现在阅读的这章和 下一章 。
第二部分, 重放设计模式 ,复习了 GoF 书籍里的很多模式。 在每一章中,我给出我对这个模式的看法,以及我认为它和游戏编程有什么关系。
最后一部分是这本书最肥美的部分。 它展示了十三种我发现有用的模式。它们被分为四类: 序列模式 , 行为模式 , 解耦模式 ,和 优化模式 。
每种模式都使用固定的格式表述,这样你可以将这本书当成引用,快速找到你需要的:
意图 部分提供这个模式想要解决什么问题的简短介绍。 将它放在首位,这样你可以快速翻阅,找到你现在需要的模式。
动机 部分描述了模式处理的问题示例。 不同于具体的算法,模式通常不针对某个特定问题。 不用示例教授模式,就像不用面团教授烘烤。动机部分提供了面团,而下部分会教你烘烤。
模式 部分将模式从示例中剥离出来。 如果你想要一段对模式的教科书式简短介绍,那就是这部分了。 如果你已经熟悉了这种模式,想要确保你没有拉下什么,这部分也是很好的提示。
到目前为止,模式只是用一两个示例解释。但是如何知道模式对 你的 问题有没有用呢? 何时使用 部分提供了这个模式在何时使用何时不用的指导。 记住 部分指出了使用模式的结果和风险。
如果你像我一样需要具体的例子真正来 理解 某物,那么 示例代码 部分能让你称心如意。 它描述模式的一步步具体实现,来展现模式是如何工作的。
模式与算法不同的是它们是开放的。 每次你使用模式,可以不同的方式实现。 下一部分 设计决策 ,讨论这些方式,告诉你应用模式时可供考虑的不同选项。
作为结尾,这里有 参见 部分展示了这一模式与其他模式的关联,以及那些使用它的真实代码。
关于示例代码
这本书的示例代码使用 C++写就,但这并不意味着这些模式只在 C++中有用,或 C++比其他语言更适合使用这些模式。 这些模式适用于几乎每种编程语言,虽然有的模式假设编程语言有对象和类。
我选择 C++有几个原因。首先,这是在游戏制作中最流行的语言,是业界的 通用语 。 通常,C++基于的 C 语法也是 Java,C#,JavaScript 和其他很多语言的基础。 哪怕你不懂 C++,你也只需一点点努力就能理解这里的示例代码。
这本书的目标 不是 教会你 C++。 示例代码尽可能的简单,不一定符合好的 C++风格或规范。 示例代码展示的是意图,而不是代码。
特别的,代码没用“现代的”——C++11 或者更新的——标准。 没有使用标准库,很少使用模板。 它们是“糟糕”C++代码,但我希望保持这样,这样那些使用 C,Objective-C,Java 和其他语言的人更容易理解它们。
为了避免花费时间在你已经看过或者是与模式无关的代码上,示例中省略了部分代码。 如果是那样,示例代码中的省略号表明这里隐藏了一些代码。
假设有个函数,做了些工作然后返回值。 而用它作示例的模式只关心返回的值,而不是完成了什么工作。那样的话,示例代码长的像这样:
bool update() { // 做点工作…… return isDone(); }
接下来呢
设计模式在软件开发过程中不断地改变和扩展。 这本书继续了 GoF 记录分享设计模式的旅程,而这旅程也不会终于本书。
你是这段旅程的关键部分。改良(或者否决)了这本书中的模式,你就是为软件开发社区做贡献。 如果你有任何建议,更正,或者任何反馈,保持联络!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论