从零开始手敲次世代游戏引擎(四)

上一篇我们在Linux上建立了Clang的编译环境。现在我们可以开始着手引擎的开发了。

软件开发有几种模式。传统的是瀑布式,就是先完成顶层的设计,然后进行细节设计和实现。这种方式有一个隐含的假设,那就是”成竹在胸”。好比一个造船厂,已经有着丰富的造船经验,对于新用户的新订单,虽然有着很多定制化要求,但是整体的技术已经十分稳定,就可以采用这种模式。另外一种常用的则是迭代开发,将每次迭代控制在一个较小可控的范围之内,每次迭代都产生一个比上一个版本进化了的,功能受限但是可执行的版本,日积月累,是一个不断试错的过程。这种方式就好比”摸着石子过河”,是一种探索式的开发方式,适用于开发经验不足的领域或者需求不定的领域。

— 脱线开始 —

本系列的目的主要是展示一个挑战的过程,就好比直播一个《血源》的游戏过程。展示也有两种方法,一种是先在线下将《血源》玩成割草游戏,然后上线展示;另外一种则是展示一个普通玩家的挑战学习过程。本系列的立意是后者。

这是因为很多事情,说是一回儿事情,做起来就是另外一回儿事情了。很多事情都是道理很简单但是操作起来就有无数的细节。就好比开发一个引擎是很难,但并不是难到里面写的都是外星文。事实上,知识都在那里,概念很多人也都知道,当代先进的商用引擎也都开源放在那里。建造一个引擎,甚至是打造一个主机平台,这里面主要是工程的问题。而这些问题,即使是开源,没有实际动手参与其中的,也很难知道。

所谓”工欲善其事,必先利其器”。在笔者的日常工作当中,遇到了很多不读平台文档,不做准备工作就开始匆匆上马开发的人员。最终他们都卡在了操作细节上,而不是所谓的大局观。有明明没有连上所有配线却在问为啥无法访问开发机的,有没有安装sdk却问编译为啥不通过的,有到了游戏快发布却不知道在哪里看控制台输出的log的,有不知道调试程序并不是一定要打包安装之后才可以进行的,有到了出补丁的时候却忘记了原始版本放在哪里的。这样的例子并不是少数。

— 脱线结束 —

虽然我们选用第二种方式,但是我们仍然需要有一个目标和基本方向。现实社会是复杂非线性的,任何模型只能是某种程度上的近似,迭代也只能发生在这个方向上。

下面就是关于这个引擎的一些基本考虑:

  1. 该引擎的设计意图是用于教学演示目的
  2. 因此代码应该简单易读
  3. 模块清晰,且容易替代,方便做各种改进和尝试
  4. 不依赖任何特定硬件,尽量使用标准技术
  5. 随时追加新校则(?)

指导本开发总体的主要书籍是

gameenginebook.com/

在具体的设计实现方面,尽量吸收当时能够获取到的最新信息。

同时当然十分欢迎感兴趣的朋友的加入。无论是通过评论的方式,投稿的方式,还是github的pull request的方式。

(– 题外话开始 –)

知乎的手机app写作功能还是十分受限,所以这两期格式上会比较单调。日后上pc修正。

(– 题外话结束 –)

一个游戏引擎的主体架构,可能随着游戏类型的丰富和游戏复杂度的提升,在最近的10-20年里有了很多的变化。比如2D到3D的进化,线性流程到开放世界的进化,确定性AI到不确定性AI的进化,卡通风格画面到电影品质画面的进化,单机到网络的变化,小团队制作到动则数百人大制作的变化,等等。

然而,如果从计算机硬件的角度来看,无论是哪种类型的游戏,其基本的流程又是十分类似的。获取外部的输入,执行某种策略,更新场景物体状态,绘制画面,输出画面。

从软件系统分类角度来看,游戏系统属于软实时系统。所谓软实时系统,就是它首先要求特定的任务在特定的时间片段内完成(保持一定的帧率)。但如果没有完成,也不会造成伤及人身的重大事故的系统。

在工业界,对于用于生产的实时系统,一般是采用实时操作系统。这种系统所执行的每个任务的执行时间都是事先设计好的。到了时间没有执行完,就会执行紧急措施。

在主机游戏开发领域,早期的游戏开发其实很类似这种情况。那时候的主机并没有什么游戏引擎的概念,连一个像样的操作系统也是没有的。游戏开发工程师们读着硬件的各种参数资料,数着byte和cycle,用一张庞大的spreadsheet计算着各种资源的存放位置和调用周期。这种风格的开发至少延续到PS2世代。在那个世代里,最强的是日本的开发商。因为他们有秋叶原,有极强的计划性。这些老头们现在仍然是日本大厂的中坚力量,然而他们显然已经被时代甩在了后面。

随着硬件的摩尔定律式的发展,游戏内容容量也出现雪崩式增长,这样的开发手法已经变得没有实际操作性了。人们已经不可能去一一指定所有的细节,取而代之的则是制定一些规则,让计算机按照这些规则自己去调度安排资源分配,这就是操作系统和引擎runtime开始导入到主机的一个重要原因。而这些是欧美的强项,游戏圈因此也出现了往欧美一边倒的局面。

另外一个方面,如此庞大的内容资源制作和管理也日渐成为游戏开发的核心问题。增加人力自然是一个办法,也是业界最先采用的方法。然而人是典型的非线性资源,每增加一个人带来的不仅仅是一个人的工资,更是增加了(n*(n-1))/2-((n-1)*(n-2))/2=n-1条沟通路径,和无数的不确定性,劳动生产率快速下降。

因此,队伍规模不能无限地扩张。于是下一个目标就是提高生产单位的生产率。加班加点从原来的忘我工作成为了现在的强制要求。

然而即使是这样也是不够的。疲劳在累积,到了一定程度人会作自由落体运动。新人补进来又是长长的适应周期。

所以剩下的办法就是改革生产工具,计算机不仅仅是用来跑游戏,还要用来写游戏。这就萌生了所谓游戏制作pipeline的概念,也是游戏制作走向工业化的标志。

知乎里有很多诸如“中国为什么没有AAA大作?”这样的问题,有很多大牛从很多方向做了解答。我觉得答得都很棒。但是我想加一条,那就是中国的游戏开发,甚至是更为广泛的软件开发,其生产工业化水平较低,这也是一个很重要的原因。

又跑远了。国内能写这种总结式批评文章的人太多,知乎上就一大把,我还是回到实际操作上。

当代引擎除了runtime,还有一个重要的组成部分就是editor。这个editor就是用来提高生产率的。在以前,游戏的各种资源必须由程序一个一个放进去。而有了editor,游戏本身的制作就可以交给程序以外的人员了。《古墓丽影4》开放了一个关卡编辑器,那个就是当代引擎editor部分的祖先之一。editor在计算机软件属于应用程序,和runtime的性质很不一样。但是,editor的性质和游戏却是很相近的。比如南梦宫的《坦克大战》,里面就是自带关卡编辑器的,而且这个编辑器小孩都能玩得很溜。

前面提到我们的引擎设计的一个要求是要跨平台。然而editor所要求的GUI部分是最难跨平台的部分之一,因为不同平台这部分的API实在是差得太远。但是我们既然要写一个跨平台游戏引擎,那么为什么不就用这个引擎来跑editor呢?这其实也是目前主流商用引擎比较广泛采用的一个办法。当然游戏的渲染引擎与GUI的绘制方式上有很多本质的差别,一些著名的商用引擎至今没有很好用的GUI控件,这个我们后面相关章节再讨论。

综合以上,我们可以确定开发顺序是先进行runtime的开发,然后是editor的开发。

根据上面写了的一般游戏的通用处理流程,我们可以很自然地想到我们将会需要下面这些模块:

  1. 输入管理模块,用来获取用户输入
  2. 策略模块,用来执行策略
  3. 场景管理模块,用来管理场景和更新场景
  4. 渲染模块,用来执行渲染和画面输出
  5. 音频音效模块,用来管理声音,混音和播放
  6. 网络通信模块,用来管理网络通信
  7. 文件I/O模块,用来管理资源的加载和参数的保存回复
  8. 内存管理模块,用来调度管理内存上的资源
  9. 驱动模块,用来根据时间,事件等驱动其它模块
  10. 辅助模块,用来执行调试,log输出等辅助功能
  11. 应用程序模块,用来抽象处理配置文件,特定平台的通知,创建窗口等需要与特定平台对接的部分

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

您正在使用您的 WordPress.com 账号评论。 登出 /  更改 )

Google photo

您正在使用您的 Google 账号评论。 登出 /  更改 )

Twitter picture

您正在使用您的 Twitter 账号评论。 登出 /  更改 )

Facebook photo

您正在使用您的 Facebook 账号评论。 登出 /  更改 )

Connecting to %s

%d 博主赞过: