前 言
游戏编程模式
在五年级的时候,我和我的小伙伴们获准使用一个放置着几台非常破旧的TRS-80s[1]的闲置教室。为了激励我们,一位老师找到了一份印有一些简单BASIC程序的打印文档给我们。
当时,计算机上的音频磁带驱动器是坏掉的,所以每次我们想要运行一些代码的时候,都不得不仔细地从头开始键入代码。这使得我们更喜欢那些只有几行代码的程序:
如果计算机打印足够多的次数,或许它会神奇的变成现实哦[2]。
10 PRINT "BOBBY IS RADICAL!!!"
20 GOTO 10
即便如此,整个过程还是充满了艰辛。我们不懂得如何编程,所以一个小的语法错误便让我们感到很费解。程序出毛病是家常便饭,而此时我们只能重头再来。
在这叠文档的最后部分,是一个真正的“怪物”:一个代码量占据几页篇幅的程序。我们思量良久,这才鼓起勇气去尝试它,不过它极为诱人——标题写着“巨魔洞穴”。我们不知道它是做什么的,不过听起来像是个游戏,还有什么能比亲手写一款计算机游戏更酷呢?
我们从没让这个程序真正运行起来过。一年后,我们搬出了那个教室(后来当我了解了一点BASIC时,才知道那只是一个供桌面游戏使用的角色生成器,而并非一款完整的游戏)。命中注定,从那之后,我立志要成为一个游戏程序员。
在我十几岁时,我的家人搞了一台装有QuickBASIC的Macintosh,之后又装了THINKC。我几乎整个暑假都在那上面倒腾游戏。自学是缓慢而痛苦的。我能轻松地让一些代码运行起来(也许是一张屏幕地图或者一个小型猜谜游戏),但随着程序增大,编码变得越来越难。
我的许多夏天都是在路易斯安那州南部的沼泽中捕蛇和乌龟来度过的。如果户外不是那么酷热的话,这将很可能是一本爬虫学的书,而不是讲游戏编程的书。
起初,我的挑战在于让程序运行起来。后来,我开始琢磨如何编写超出我大脑思考范围的更大些的程序。我开始试图寻找一些关于如何组织程序的书籍,而不只是读一些关于“如何用C++编程”之类的书籍。
几年很快过去,一位朋友给了我一本书:《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)。终于来了!这就是我从青少年开始便一直寻找的那本书!我一口气将它一字不漏地读完了。虽然我仍纠结于自己的程序,但是看到别人也如此挣扎并提出了解决方案,也如释重负。原本赤手空拳的我终于有工具可使了。
这是我和这位朋友第一次见面,在5分钟自我介绍之后,我坐在他的沙发上,在接下来的几个小时里,我聚精会神地阅读而完全忽视了他。我感觉从那以后自己的社交能力还是至少有那么一丁点儿提升的。
在2001年,我得到了自己梦寐以求的工作:EA(Electronic Arts)的软件工程师。我迫不及待地想看一下真正的游戏,以及工程师们是如何组织它们的。像Madden Football这样的大型游戏到底是个什么样的架构?不同系统之间是怎么交互的?他们是怎么让一套代码库在不同平台上运行的?
分解阅读源码是一种震撼人心且令人惊奇的体验。图形、人工智能、动画和视觉效果方面,都有十分出众的代码。我们公司有人懂得如何榨取CPU的每一个周期并加以善用。一些我甚至不知道能否实现的东西,这些家伙一个早上就能搞定。
但是这些优秀代码所依托的架构往往是事后想出来的。他们太专注于功能以至于忽视了组织架构。模块之间的耦合现象很普遍,新功能往代码库里见缝插针,而不顾其是否契合。这些所见令我幻想破灭,看起来许多程序员,就算他们心血来潮地翻开过《设计模式》一书,恐怕能看完单例就很不错了。
当然,也不是真的那么糟糕。我曾设想游戏程序员们坐在放满白板的象牙塔中,连续几周冷静地讨论代码架构的细节。实际情况是,我眼前这份代码是别人在紧张的期限里赶工出来的。他们尽了自己最大的努力,同时,我逐渐认识到,他们竭尽全力的结果通常是编写出了十分优秀的代码。我写游戏代码的时间越长,就越能发现隐藏在这些代码之下的可贵之处。
遗憾的是,“隐藏”一词往往说明了问题。宝藏埋在代码深处,而许多人正在它们之上路过(优秀的代码被许多人视而不见)。我看到过同事努力想改造出一个好的解决方案,那时,他们所需要的示例代码就隐藏在他们脚下的代码库之中。
这个问题正是本书力图解决的。我挖掘并打磨出自己在游戏代码中所发现的最好的设计模式,在此一一呈现给大家,以便我们将时间节省下来创造新事物,而不是重新造轮子。
目 录
第1篇 概述
第1章 架构,性能和游戏
1.1 什么是软件架构
1.2 有什么代价
1.3 性能和速度
1.4 坏代码中的好代码
1.5 寻求平衡
1.6 简单性
1.7 准备出发
第2篇 再探设计模式
第2章 命令模式
第3章 享元模式
第4章 观察者模式
第5章 原型模式
第6章 单例模式
第7章 状态模式
7.1 我们曾经相遇过
7.2 救星:有限状态机
7.3 枚举和分支
7.4 状态模式
7.5 状态对象应该放在哪里呢
7.6 进入状态和退出状态的行为
7.7 有什么收获吗
7.8 并发状态机
7.9 层次状态机
7.10 下推自动机
7.11 现在知道它们有多有用了吧
第3篇 序列型模式
第8章 双缓冲
第9章 游戏循环
第10章 更新方法
第4篇 行为型模式
第11章 字节码
第12章 子类沙盒
第13章 类型对象
第5篇 解耦型模式
第14章 组件模式
第15章 事件队列
第16章 服务定位器
第6篇 优化型模式
第17章 数据局部性
第18章 脏标记模式
第19章 对象池
第20章 空间分区