建立一个备忘录,方便以后参考。

体验

2D动作与动画

最近注意到2D游戏上的,有关动画的一个细节。2D游戏中,角色或NPC移动的最小单位一般为一个格子,角色或NPC的动作都由一组动画来表示,比如行走,施法,普通攻击。施法的时候一般角色本身不会有大范围的动作,主要是通过特效来表现魔法的效果。而普通攻击就不一样了,有些时候为了表现出稍微华丽一些的攻击动作,就不得不考虑增加动作幅度

一个格子由若干个像素组成,格子的形状不一定是矩形

比如角色手里拿一把刀,最基本的攻击动作就是站在原地挥一下刀,在这种情况下,人物的动作动画基本上不会超出当前格子。花哨一点,来个箭步,再挥刀,那么这个动作的动画就有可能会超出当前格子。若是攻击范围都为一(即只能攻击到周围一个格子以内的物体),当两个角色对砍的时候,这种情形势必会造成两个动画出现重叠的现象。对砍时,动画中挥出去的武器部分发生重叠似乎可以接受(或许也是一种合理的重叠),但是若是发生两个人身体主干的重叠,那么就有点影响视觉体验了。 一个简单的办法是为每一个动画设定一个实体范围,这个范围包裹了角色的主干,不允许出现重叠绘制,当屏幕上有多个角色要绘制动画时,根据触发时间上的先后顺序,对各个动画的播放位置进行抢占式的判定。比如A先触发,根据A的动画实体范围,标记一些格子,然后B再触发时,若是B的实体范围与A发生冲突,那么B需要进行偏移。 若是角色的攻击氛围允许在适当范围内的浮动的话,那么还可以采用另外一种办法。当A与B相邻时,只允许触发那些不会超过当前格子区域的动画(比如原地挥刀),当A与B中间隔了一个格子的时候,则自动触发攻击氛围为2的动画(比如箭步挥刀)。 记得《传奇》里面,战士的普通攻击动作只有一种,好像是原地蹲马步挥刀。当然,那个年代,玩《传奇》的人们,最关注的可能并不是画面……

文字表述 - 生产者与用户

大部分时候,游戏开发者本身也是一个玩家。讨论游戏,是游戏设计过程中必不可少的一个步骤。同其他玩家一样,在讨论的过程中,一般都会为游戏里面的物品或元素约定一个简称,就拿《传奇》来说,记得好像补血的药品在游戏里是叫“金创药”吧,但是我们一般都称之为“红”(或者“红药”),同理,另一种称为“蓝”。这可以理解为口语书面语的区别。一款游戏,应该是一个很正式的产品,尽管玩家都称这些为“红”或者“蓝”,但是游戏本身还是应该保留自己的特点。举个例子,在老一辈的网游界里,你一说“屠龙”,有几个人不会联想到《热血传奇》?

时至今日,一说起“无极棍”,“骨玉”,“冰咆哮”,我的思绪都能回到那段沉浸在传奇游戏里的日子。

总之,一个游戏里面的一切设定,都应该当作一个特色来对待,正式的书面语能表明开发者对游戏的重视,反之,口语化的表述,会给玩家一种儿戏的错觉。至少在我看来,如果在游戏中,看到类似“红”,“蓝”这样的口语化表述,我很可能会觉得这是一款半成品的游戏。

在设计与实现之前

在一步一步实现ZFXEngine的过程中,每次回过头来审视代码,想添加一些功能,总是会觉得相当麻烦,有的是工作量可能太大,有的则是会影响现有架构,总觉得一开始如果没有考虑到要加入这个功能的话,后面再想加入就会特别困难。 另一方面,如果一开始在设计引擎的时候,就想囊括所有最新的技术与最全的功能,我觉得也是不现实的,可能压根儿就没法实现。 因此,产生了这样的思考:能不能在保证最佳扩展性的情况下,在工作开始前,指定某些决策,以及在引擎设计与实现的初期,忽略某些功能,或者说先放弃某些功能,从而达到最佳的开发速度、质量,以及兼容性。

耦合度

我觉得可以用耦合度来判断某个模块或功能是否必须在引擎设计与实现的初期就加以考虑。 对图形渲染接口的封装,可以作为一个例子。只要我们在设计初期,定义了良好的图形渲染接口,那么我们就可以不考虑具体图形接口的实现。我们可以在初期用OpenGL实现这个接口,当需要用D3D实现的时候,我们再用D3D实现也不迟,完全不会影响现有架构。 因此,我们可以总结出这样一个规律:实现一组接口,基本上不会对原有架构造成影响 图形渲染引擎,与游戏引擎有较高的耦合度,但是通过定义图形渲染接口,则可以实现解耦,因而就不用在游戏设计阶段苦恼于该选用OpenGL还是D3D。 对于原子类型定义,我们也可以视为一种解耦方法,通过typedef语句,使我们可以在一个地方控制所有的数据类型。 可以认为,耦合度高的,需在初期阶段加以考虑,而耦合度较低的,则可以在初期忽略掉。

初期决策

无论如何,有一些功能是在设计初期需要考虑取舍的。 就目前我的经验来说,有下列功能是需要考虑的。

  • 国际化与本地化(I18n, L10n) 无论是否需要国际化,都应该尽量避免在游戏代码中,直接使用硬字符串。对于需要国际化,而又不得不在源代码中使用硬字符串的软件,可以使用像gettext这样的函数库进行翻译。 Linux/Unix下很容易安装gettext函数库,对于Windows环境,可以试试由Michele Locati提供的二进制版本。 当然,上面提到的硬字符串只是针对于会与用户进行交互的字符串,对于只是在程序内部使用的字符串,无需特殊处理。比如:程序中用来表示着色器变量名的字符串。

  • Unicode 与国际化对应的是使用宽字符集。用惯了charstrlen,可能一开始会有些不习惯使用wchar_twcslen。但是很显然,这种转换也是必须的。

  • 跨平台 从程序开发的角度来讲,应该是尽量实现跨平台,但是实际上,是否支持跨平台,应该根据具体需求来进行取舍。 实现跨平台,无论是对程序结构,还是对后期维护和移植,都是有益的。但是,显而易见的会增加初期开发的工作量。而且,对于有些游戏来说,可能根本不需要跨平台。比如国内大部分网络游戏,其用户都是使用的Windows系统,所以完全没有必要实现跨平台。

工作流

三体

在一款游戏的开发维护过程中,存在着三种基本的职能角色:程序美术策划

  • 程序主要负责游戏功能的实现
  • 美术负责游戏的视觉表现
  • 策划负责游戏的核心思想

关于三者的作用,我只想说:缺一不可。具体谁更重要,似乎是一个没有意义的无止境的争论。 这三种职能角色既可以由一人包揽,也可以由一个团队里面不同的人承担。

关于游戏配置

在游戏开发的过程中,对于某些功能,一般会存在一些配置,由策划来配置数据,然后程序读取配置。这是一种策划对游戏的进行控制的办法。 关于这些配置,程序会和策划商量好某种数据结构,然后策划按照这种结构填写数据。 配置的承载体可以是XML文件、JSON文件,亦或是Excel文件等。当使用XML或是JSON的时候,一般需要自己组织结构。对于XML,配置可能如下:

<Config>
    <Person>
        <Name>Chris Cheng</Name>
        <Email>gemini2015@hotmail.com</Email>
    </Person>
    <Person>
        <Name>Asuka</Name>
        <Email>asuka@nerv.com</Email>
    </Person>
</Config>

在这个配置中,策划需要填写的有效数据只有<Name><Email>,其余的都是用于组织结构的标签。对于少量配置而言,手写这些标签是完全没有问题的,但是对于大量的配置,手写这些标签很容易出错,而且无疑也是很大的工作量。

我认为,当配置的数据结构确定第一版格式之后,应当尽早实现自动化工具。此处的自动化工具是指使用诸如WPF这样的适合快速GUI程序开发的框架构建一个程序,策划使用这些程序录入配置数据,而不是直接编写配置文件。 使用自动化工具有以下好处:

  1. 减少不必要的数据输入,比如上面提到的标签。策划只需要输入有效数据。
  2. 便于数据管理,后期可以通过工具实现对配置数据的增删改查等操作。
  3. 便于配置格式的升级。将数据结构与具体的承载分离,也就是说同一份配置数据可以很方便的输出多种格式的配置。

我有一个观点,即策划应该对游戏进行控制,但是这种控制应该在一个由程序设定的范围内进行。 比如上面讲到的游戏配置,程序需要的是策划提供的配置数据,而不是配置文件。由人为直接编写提供的配置文件,可能会存在各种各样的错误,使用自动化工具的话,能在最大程度上保证不会出现配置格式错误。

也许,程序编写一个自动化工具可能会需要一些时间,但是,从长远上来讲,一个好的自动化工具,可以减少很多程序Debug的时间。