狭义的游戏对象是指游戏世界中所能看到及可交互的对象,如玩家、怪物、物品等,我们这里也主要讨论这类对象在服务器上的组织及实现。
在大部分的MMOG中,游戏对象的类型都大同小异,主要有物品、生物、玩家等。比如在wow中,通过服务器发下来的GUID我们可以了解到,游戏中有9大类对象,包括物品(Item)、背包(Container)、生物(Unit)、玩家(Player)、游戏对象(GameObject)、动态对象(DynamicObject)、尸体(Corpse)等。
在mangos的实现中,对象使用类继承的方式,由Object基类定义游戏对象的公有接口及属性,包括GUID的生成及管理、构造及更新UpdateData数据的虚接口、设置及获取对象属性集的方法等。然后分出了两类派生对象,一是Item,另一是WorldObject。Item即物品对象,WorldObject顾名思义,为世界对象,即可添加到游戏世界场景中的对象,该对象类型定义了纯虚接口,也就是不可被实例化,主要是在Object对象的基础上又添加了坐标设置或获取的相关接口。
Item类型又派兵出了一类Bag对象,这是一种特殊的物品对象,其本身具有物品的所有属性及方法,但又可作为新的容器类型,并具有自己特有的属性和方法,所以实现上采用了派生。mangos在实现时对Bag的类型定义做了点小技巧,Item的类型为2,Bag的类型为6,这样在通过位的方式来表示类型时,Bag类型也就同时属于Item类型了。虽然只是很小的一个技巧,但在很多地方却带来了极大的便利。
从WorldObject派生出的类型就有好几种了,Unit、GameObject、DynamicObject和Corpse。Unit为所有生物类型的基类,同WorldObject一样,也不可被实例化。它定义了生物类型的公有属性,如种族、职业、性别、生命、魔法等,另外还提供了相关的一些操作接口。游戏中实际的生物对象类型为Creature,从Unit派生,另外还有一类派生对象Player为玩家对象。Player与Creature在实现上最大的区别是玩家的操作由客户端发来的消息驱动,而Creature的控制是由自己定义的AI对象来驱动,另外Player内部还包括了很多的逻辑系统实现。
另外还有两类特殊的Creature,Pet和Totem,其对象类型仍然还是生物类,只是实现上与会有些特殊的东西需要处理,所以在mangos中将其作为独立的派生类,只是实现上的一点处理。另外在GameObject中也实现有派生对象,最终的继承关系图比较简单,就不麻烦地去画图了。
从我所了解的早期游戏实现来看,大部分的游戏对象结构都是采用的类似这种方式。可能与早期对面向对象的理解有关,当面向对象的概念刚出来时,大家认为继承就是面向对象的全部,所以处处皆对象,处处皆继承。
类实现的是一种封装,虽然从云风那里出来的弃C++而转投C的声音可能会影响一部分人,但是,使用什么语言本身就是个人喜好及团队整体情况决定的。我们所要的也是最终的实现结果,至于中间的步骤,完全看个人。还是用云风的话说,这只是一种信仰问题,我依然采用我所熟悉的C++,下面的描述也是如此。
随着面向对象技术的深入,以及泛型等概念的相继提出,软件程序结构方面的趋势也有了很大改变。C++大师们常说的话中有一句是这样说的,尽是采用组合而不是继承。游戏对象的实现也有类似的转变,趋向于以组合的方式来实现游戏对象类型,也就是实现一个通用的entity类型,然后以脚本定义的方式组合出不同的实际游戏对象类型。
描述的有些抽象,具体实现下一篇来仔细探讨下。