游戏引擎的功能估计在具体动手之前,设计和实现基于命令的语言的第一步就是要解决以下两个问题:
● 游戏引擎具体能够实现什么功能。
● 游戏引擎的脚本具体需要实现什么功能。
区分游戏引擎能够具体实现什么样的功能以及游戏脚本实际需要完成什么样的功能是非常重要的。因为游戏引擎能够具体实现的功能并不意味着游戏脚本可以访问或者调用。所有那些你想让游戏脚本可以访问的功能都应该封装进一个命令处理程序(command handler)中。命令处理程序是一小段代码,它负责具体执行和每条命令相关联的代码。
例如,下面来分析一个简单的,2D角色扮演游戏的游戏引擎,它类似于你在Nintendo、Super Nintendo和Sega Saturn中看到的游戏引擎。这些游戏都是基于那些由称为tile的小正方形图形拼成的二维游戏地图。这些地图定义了游戏中每个游戏场景的背景和环境,而且它们可以向4个方向滚动。在这些地图的上面,那些基于精灵构建的角色(sprite-based characters)可以四处行走并可以和其他的角色进行交互,在那些潜在的地图中情况也与此相同。就像你在第2章中所了解到的那样,这些游戏中一个非常重要的地方就是游戏中的非玩家角色(non-player characters,NPC)。这些非玩家角色需要形象逼真,至少也要在一定程度上满足这个要求,因此它们就不能只是一动不动的站在那儿等着游戏玩家来动手处理它们。它们也一定要按照自己的方式四处行走,这些通常被表示为控制它们具体行为的代码。
对于这个例子而言,所有列在表3.1中的命令可能对于脚本都很有用处。
表3.1 RPG引擎的脚本命令
命 令 | 描 述 |
SetNPCDir | 设置NPC面临的方向 |
MoveNPC | 沿X轴和Y轴朝特定方向移动NPC |
Pause | 使NPC在特定时段内静止站立( |
ShowTextBox | 在文本对话框显示一行特别的文字;用于对话 |
所有这些命令都需要具有某种形式的参数来辅助指导它们的具体行为。这些参数可以被表示为下面两种数据类型——整型和字符串类型。参数之间并不是用逗号,而是使用一个单独的空格符来隔开的。参数和命令本身也有一个单独的空格隔开,这就意味着在这种语言中命令整体的语法结构如下:: D" /) y* U# E% ]7 @
Command Param0 Param1 Param2
所有命令都需要严格地遵守这一语法结构。这种语言的形式绝对是不自由的,所以也不允许随意使用空格符。
单纯使用4条命令,这种语言的语言特征就几乎不可能丰富起来。然而,你却极有可能对于这些简单命令实现的效果感到惊讶不已。看下面这一段脚本:
SetNPCDir "Up"
MoveNPC 0 -20
Pause 200
SetNPCDir "Left"
MoveNPC -20 0
Pause 400
SetNPCDir "Down"
ShowTextBox "Hmmmmm... I know I left it here somewhere..."
Pause 400
通过观察这些代码你能说出它具体实现了什么功能吗?通过使用仅仅几行这种简单的脚本代码,我已经定义了正在四处寻找某种东西的一个非游戏玩家的具体行为。他由某个给定的地点出发,面对某个特定的方向,然后向上移动(这个实际上就是指北方)。他沿着这个方向行走了20像素,暂停一下,然后再向左(西)行走20像素。这个时候他再次暂停下来,并且时间要稍微长一些,最后他转向摄像机的方向(下或者是南),并且对他所丢失的东西发表一句简单的评价。游戏脚本随后稍微停顿一下以使得游戏玩家有机会阅读这个信息,然后通常脚本返回到循环的起始状态并重新执行。
注释:或许你会疑问为什么非玩家角色脚本中如Up和Down这样一些主要的方向信息都要使用字符串形式来表述,这是因为该语言并不支持像C中由#define定义的和C++中由const定义的这些符号常量。如果创建一个SetNPCDir命令使得它可以接受代表具体方向的整型代码(例如0~3)也很容易,但是要记住这些任意的数据要比直接使用字符串困难得多。但是,不管怎样,这都仍然是一个很不理想的解决办法,因此你要接着向下阅读——第4章中会再次涉及到这个问题。
对于这样一个简单的脚本系统和这样一个更加简单的脚本,这已经是一个相当逼真的小型游戏角色。你可以想象一下,如果你能在这里添加更多的命令,那么你就能使你的非玩家人物变得很具有个性。所以现在我们有理由相信你已经开始明白使用脚本编程,你不需要太多复杂的东西就可以达到相当好的效果。
载入和执行脚本
每个游戏脚本在生存期跨越了好几个阶段,所有这些在图3.3中都以图例的形式进行了解释。首先,游戏脚本被载入。在这个简单的游戏语言中,垂直方向的空白和注释是不允许的,这就意味着需要将源文件中的每行代码载入到字符串数组里面的每个单独的元素。一旦这个过程完成了,这个数组就包含了该脚本in-memory的一个备份并准备执行。参看图3.4以获得对于游戏脚本in-memory格式的一个更加形象的理解。
图3.3 游戏脚本的生存期
注:脚本由一个字符串数组中载入,并通过脚本控制器(script handler)加以执行,最后实施对于游戏引擎的控制。
图3.4 内存中的游戏脚本
一旦被存放到内存当中,游戏脚本就可以通过让每行代码都通过脚本处理程序(script handler,或者是executor,以及其他的各种名称)来使其获得执行。脚本处理程序负责处理每条命令,读入指令参数等。一旦一条游戏命令和它的参数被处理和识别了,脚本处理程序就会完成与该条游戏命令相关联的具体任务。例如,对于指令MoveNPC而言,脚本处理程序用两个整型变量(X和Y)在游戏引擎内部直接修改非玩家角色的数据。从这一点上说,游戏脚本成功地控制了游戏引擎。
基于命令的脚本语言始终都是顺序执行的。这就意味着执行过程是从一条命令开始(第0行)直到最后一条命令结束(在图3.4所示的例子中是第5行)。在这个过程的每一步当中,表示脚本中当前行代码的一个全局变量都会被更新以反映将要处理的下一条命令。这个全局变量可能会被称为g_iCurrLine,它的表示意义是current line。当这个过程以循环的方式进行重复时,这个脚本将会连续地快速执行以用于模拟实际代码的执行过程。一旦到达了脚本的最后一条命令,脚本就会停止运行或者返回到开始的地方并重新运行。图3.5解释了一个脚本的执行过程。
图3.5 一个脚本的执行过程
脚本循环
当到达了最后一条命令的时候,你的脚本到底是应该停止还是应该继续循环呢?对于这个问题,没有一个固定的答案,因为回答这个问题要取决于当时脚本的具体情况。例如,我们继续前面有关角色扮演游戏引擎的话题,一个定义武器或者物品行为的脚本就应当执行一次并在脚本末尾迅速终止。当游戏玩家使用物品时,游戏脚本就需要执行一次以允许物品完成任务或者执行相应的动作,然后立即结束。除非是游戏玩家具体要求它这么做,或者是该物品具有某种持久的特性(例如一个应该一直燃烧着的火炬),否则该物品不应多次执行。"
提示:游戏脚本的循环以及这些脚本的行为看起来具有可预测性的问题具有很多种解决办法。第一种解决办法就是,增加游戏脚本的长度以使得它在进行循环之前可以产生足够数量的独特行为,这样游戏玩家就没有时间(或者是兴趣)注意到它是按照一定的固定模式执行的。此外,我们还可以编写很多小型的脚本,它们以一种具有细微差别的方式实现相同的行为。这些脚本然后由游戏引擎随即的载入进来以产生一些真正的(或者是几乎真正的)随机行为。
Z0 P- T$ e' g8 V- B
应当循环执行的脚本主要就是那些负责控制与背景相关的实体或者其他环境实体的游戏脚本。例如,非玩家人物代表着游戏世界中活着的居住者,这就意味着他们应当连续不断地四处行走以使游戏玩家觉得他们一直都没有见过面。因而,当非游戏角色脚本执行完最后一条命令时应该立即返回到第一条命令,这样的话它们的行为从来不会停止。毫无疑问,这也就意味着循环的游戏脚本迟早都会被识别出来,这或许不是一件什么好事情。可是,我并没有说除了这些缺点以外基于命令的脚本就不会是一件好事情。
一、从D&D看游戏的底层设计
把一个所谓的游戏意义上的伟大创意在游戏产品上付诸于实现的前提,是所有的设计应该符合游戏工业设计规范。
——龙云峰《EEE&Lumines: Design for Business》
这是我第一次看到有人这么明确且重视地提出游戏工业设计规范。在中国游戏发展这么多年的情况下,到2006年才由一个入行不久的“准老人”提出,对于所有在职的“老人”和“大师”们,都是一种绝妙的讽刺。
可能很多玩家都奇怪,为什么一个国产游戏会拖期再拖期呢?为什么拖期之后出来的却是个Bug不断的半成品呢?为什么一款网络游戏开发到后期,连画面风格都要做出调整呢?游戏开发目前几乎所有项目的症结,归根结底都与游戏设计的架构和流程有关。其实玩家们不知道,在国内游戏项目的进程中,下面这些糟糕的状况经常会出现:
项目中期发现,如果编辑器支持一个特殊功能将能节省美术1/3的工作量
2)做到第25个月发现所有美术风格相比某游戏已完全落伍,不得不重做;
3)你和所有的人都知道游戏有什么功能,但没有人能说出游戏为什么好玩;
4)一个程序的离职导致全部渲染底层需要重写;
5)你的MMO内测中,发现玩家只要1星期就能练到100级,而这是游戏的最高级别;
6)游戏最终版本与提案书对比,只有不到30%的功能得以实现。
这些只是几个我曾经听到的例子,而很多更加荒诞的情况都在不断上演、不断重复。我曾经跟一个在做项目管理的朋友说过,我们一直在重复你们过去曾经犯下的错误。似乎所有团队都必然要交这样或那样的学费,可悲的是更多的人交了学费仍不反省,仍然采取侥幸态度忽视游戏初期设计的作用。也因此,我们今天看到的国产游戏成功者仍然寥寥无几。#
要避免后期开发中的混乱局面,在游戏设计的初期,就需要首先建立软件工程规范化的概念。什么叫软件工程?它是一门研究用工程化方法构建和维护有效的、实用的和高质量的软件的学科。它有三大要素。#
1.目标:生产具有正确性、可用性及开销合宜的产品。
过程:生产一个最终能满足需求且达到工程目标的软件产品所需要的步骤。
3.原则:是指围绕工程设计、工程支持及工程管理在软件开发过程中必须遵循的原则。
网游组织 O; r+ Z; @: ]
游戏软件的开发与其他软件开发相同,都要符合软件工程的规律。游戏的最根本本质是一个软件,文化产品只是软件完成后的附加属性——很显然的,OpenGL不仅能用于开发主视角射击游戏,也能开发工业CAD软件甚至远程医疗软件。商业软件的系统分析是针对用户实际的特点,来决定用户的现实需求如何能在软件开发中实现,而游戏软件的开发也是同样的道理。一款游戏是否能顺利开发完成,取决于它的结构是否符合软件工程规范,这是降低游戏开发难度和项目复杂度的前提。因此,我将游戏设计符合软件工程的要求,定义为游戏工业设计规范的一个基本条件。
而这对现在的中国游戏人而言,无疑是一个非常苛刻的要求,或许更有人会说这在目前的国内游戏行业也是个空想。但我们不妨仔细研究一下D&D这种老牌的桌面游戏规则吧!它至少符合一个严格的软件工程所需要具备的基本特征。仔细研究D&D,你会发现,所有的对象,通过基本属性、天赋、适用规则等(内涵构件)进行定义;通过规则操作,如魔法攻击(接口)进行相互作用;通过模板、种族、职业(类关系)进行衍生和统一。由于设计者将本来错综的游戏世界高度概括成数字化的规则(生物/人造/自然物件的基本属性和基本属性作用规则),因此在面对整个游戏世界这个巨大的复杂系统时,D&D具备几乎无限的扩展能力,可以适应不同科学发展度,不同文化的背景设计。
理论上,构建一个虚拟的世界,它的基本要素越是高度概括和定义的,那么底层设计工作的重用性就越高,扩展性也越大,同时,由于每次依靠本层次控件和规则构成往上一个层次时都可能与最初的设想有极小的偏差,因此最终层次的表象控制就越难。如果我们把当前的宇宙视为一个游戏项目,那么,上帝至少在设计之初将“夸克”视作最底层的材料,而我们看到的整个世界都是由几种基本的“夸克”构成的(看来上帝的美术工程师很省工)。由于层次非常多,这个世界最后的面貌很可能与上帝的提案书差距非常大。当然,上帝可以在最高层直接添加规则来更改这个差距。*
D&D代表了目前游戏设计能够高度概括到的极限(或许《进化》能打破这个纪录,还没有看到游戏,不知道具体情况)。我们做游戏设计,没有必要做到这个层次,只需要抽象到玩家看到的具体控件的下面一层就可以。例如MMO中有设计纸娃娃的需求,里面有衬肩,那么,我们只要比常用的做法更进一步,将衬肩再向下一个层次,分为贴图风格、形状、特效种类、特效颜色4个基本控件,那么,只要每个控件做少量几种就能组合成很多种类的衬肩,这样规划可大量减少美术的工作量。而常规做法只能是一个个衬肩去建模和绘制。
概括和定义底层是游戏设计对商业需求分析后最简单的一个步骤。在分析商业需求过程中,我们可针对各个方面抽象出类似的关键问题:
1)NPC、怪物、Boss和玩家角色是否属于共同的类?如果是,这个类如何定义?其子类如何定义和区分,基本属性、骨骼、模型、纸娃娃、动作是否通用?各子类是否有必要定义各自的子类?这些所有定义对于美术和程序工作的影响何在?
职业、种族作为通用模板如何对上述的类中的对象进行作用,其作用是否与子类的定义相关?
3)作为场景设计的需求,有多少建筑对象以构件组合方式可以作出变化?如是,组合需要支援多少种风格?有必要单独设计的建筑有多少?
4)有无可能以一种统一的升级规则操作基本属性来控制所有的平衡?
这种问题还有很多,根据游戏类型的不同,进行设计时的需求也有很大变化。(
游戏设计符合软件工程的要求,需要项目负责人有基本的软件工程知识,并有相应领域的专家加以配合。很多Boss和Leader喜欢拿到提案书就开始督促手下人干,事实上,如果给大家几个月的时间实现一个规范的工业设计,就能避免以后无数的问题,节省大量返工的成本。
前面说到的是游戏开发这个项目的初步设计问题,接下来我想谈一下我对于游戏设计过程具体管理的看法。
游戏工业的理想状态,应该是流水线生产、精益生产、个体创造的结合,在策划阶段、游戏架构阶段、试生产阶段、测试阶段需要采取不同的策略,从而最大程度降低风险、降低成本及控制开发时程。注意“面向过程的管理”这个精益生产的实质,正是游戏开发未来所必须追求的目标,也是实施游戏工业设计规范所不可缺的部分。长久以来,游戏业内的管理是“面向人的管理”或“面向目标的管理”,甚至有的连目标管理都没有,而不用说进行真正的过程管理。
肯定有读者会说:谁说中国游戏开发没有过程管理?没有月表么?没有开发计划么?没有工作日志么?我要说的是,并不是表述了过程就可自认为进行了过程管理,也不是每天跑去问程序进度如何就是做了过程控制。“面向过程的管理”包括非常多的技巧和细节,这需要管理者去研究、规划和控制。
后面开始废话了......:-(