loop_in_codes

低调做技术__欢迎移步我的独立博客 codemaro.com 微博 kevinlynx

MMO游戏对象属性设计

MMO游戏对象属性设计

Author: Kevin Lynx
Date: 5.2.2011

一般的MMORPG中,游戏对象主要包括怪物和玩家。这两类对象在经过游戏性方面的不断“进化”后,其属性数量及与之相关的逻辑往往会变得很巨大。如何将这一块做得既不损失效率,又能保证结构的灵活、清晰、可维护?本文将提供一种简单的结构。

原始结构

最原始的结构,极有可能为这样:

Player:     +---------------+
            | property-1    |
            +---------------+
            | property-2    |
            +---------------+
            |     ...       |
            +---------------+
            | operator-1    |
            +---------------+
            | operator-2    |
            +---------------+
            | ...           |
            +---------------+

也就是,一个对象为一个C++类,然后里面直接塞满了各种属性名,然后是针对这个属性的逻辑操作(函数)。其结果就是Player成为巨类。针对这个情况,一直以来我觉得可以使用一种简单的方法来拆分这个类。冠以官腔,称之为Entity-Component-based Desgin。产生这种想法和我的个人技术积累有一定关系,见下文。

Policy-based Design

Policy-based Design,基于决策的设计。这个概念来源于<Modern C++ Design>。虽然这本书讲述的是针对C++模板的使用及设计技巧。但这种思想依然被我潜意识般地用在其他地方。Policy大致来说就是一个小的组件(Component)。它努力不依赖于其他东西,它可能就是个简单的类,它拥有极少的数据结构,及针对这些数据的极少操作接口。举例而言,玩家MP的自动回复功能,就可封装为一个Policy。将许多Policy组合起来,就可完成一个复杂的功能。

这种思想还可指导很多程序结构方面的设计。例如在做功能的接口拆分时,就将每个函数设计得足够小,小到单纯地完成一个功能。一个功能的入口函数,就将之前实现的小函数全部组合起来,然后共同完成功能点。

当然,<Modern C++ Design>里的Policy在表现形式上有所不同。但其核心思想相同,主要体现在 组合 特点上。

Entity-Component-based Design

Entity-Component-based Design按照google到的文章,严格来说算是与OOP完全不同的软件设计方法。不过在这里它将按照我的意思重新被解释。

如果说Policy-based Design极大可能地影响着我们平时的细节编码,那么Entity-Component则是直接对游戏对象的结构设计做直接的说明。 一个游戏对象就是一个Entity。 Entity拥有很少的属性,也许仅包含一个全局标示的ID。 一个Component则是Entity的某个行为、或者说某个组成部分。 其实说白了,以玩家为例,一个玩家对象就是一个Entity,而一个MP的自动回复功能就可被包装为一个Component。这个Component可能包含若干与该功能相关的数据,例如回复时间间隔,每次的回复量等。我们往玩家对象这个Entity添加各种Component,也就是给玩家添加各种逻辑功能。

但是,Component之间可能会涉及到交互,玩家对象之外的模块可能也会与玩家内的某个Component交互。子功能点的拆分,不得不涉及到更多的胶水代码,这也算一种代价。

游戏对象属性设计

这份属性结构设计,基本就是参考了上面提到的设计思想。整个系统有如下组件:

Entity:    +-------------------+
           | property-table    |
           +-------------------+
           | component-table   |
           +-------------------+
Property:  +-------------------+
           | observer-list     |
           +-------------------+
Component: +--------------------+
           | logic-related data |
           +--------------------+
           | logic-related func |
           +--------------------+

意即,所有Entity都包含一个属性表和组件表。这里的属性表并非硬编码的属性数据成员集合,而是一个key-value形式的表。Property包含一个观察者列表,其实就是一系列回调函数,但是这些观察者本质上也是组件,后面会提到。Component正如上文描述,仅包含Component本身实现的功能所需要的数据和函数。整个结构大致的代码如下:

class Entity {
private:
    GUID id;
    std::map<std::string, IComponent*> components;
    std::map<std::string, Property*> properties;
};
class Property {
private:
    std::string name;
    Value val;
    std::vector<IComponent*> observers;
};
class IComponent {
public:
    virtual bool Operate (const Args &args) { return false; }
    virtual void OnNotify (const Property &property, const Args &args) {}
protected:
    std::string name;
    Entity *entity;
};

属性本身是抽象的,这完全是因为我们将属性统一地放在了一个表里。从而又导致属性的值也需要继续阅读

posted on 2011-05-02 19:19 Kevin Lynx 阅读(6358) 评论(18)  编辑 收藏 引用 所属分类: game develop模块架构

评论

# re: MMO游戏对象属性设计 2011-05-02 20:19 so

MUD游戏编程里也有属性集这样的设计。灵活。不过访问速度上肯定没有直接定死属性来得快。  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-02 20:36 Kevin Lynx

@so
加了个“继续阅读”指向我那个独立博客。- -| 你都要在这里留言。  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 10:33 lin_style

有个问题:是否代码行数多、属性多,就代表他的逻辑一定是复杂的?一定要拆分?  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 12:02 饭中淹

你那个独立博客在CHROME上会标红标骷髅头。

  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 12:03 Kevin Lynx

@lin_style
基本上是。虽然逻辑不一定复杂,可能仅仅是大量功能的堆积。但其维护性肯定不好。回忆一下当你刚接手熟悉一个项目代码时,看到一个巨类时的感觉。  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 12:11 Kevin Lynx

@饭中淹
Linux下的chrome看没有什么骷髅头啊。。- -|  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 12:51 lin_style

@Kevin Lynx
如果能够一遍就看懂“巨类”,我可能觉得这种分类方式是对的。比如人物属性,人物本来就有这么多属性啊。而且这些属性放在一起,并没有很复杂的读取逻辑,即使有不同的功能拓展,那也是每个功能类自己的模块化问题。你文中,"ClientUpdater" “HP”,从概念上都分成独立的属性模块."ClientUpdater"有必要这么做,但是也可以看成一个功能模块类去维护它,况且它也是属于游戏玩法类的,放在属性接口层也不一定合适。而"HP",是一个很清晰的概念,不需要专门的封装它,即使有hP1~HP1000这么多属性,也没有带来多高的复杂读。如果仅是凭借自己的编程习惯去封装,那这个过与不过的度怎么区分呢?  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 13:57 Kevin Lynx

@lin_style
复杂性和可维护性不仅体现在本项目,一般一个团队的下个项目就是在上个项目的基础上改。所以希望把这些游戏相关的东西尽量独立出来。理想情况下是到了下个项目可以直接通过移除一部分模块添加一部分模块即可。

当然,如你所说,确实存在度的把握问题。我现在是打算把基础属性(例如坐标)写死,或者通过本文的机制在程序里添加;其他属性(主要是战斗属性、什么中毒抗性啊、暴击伤害比率啊)放在脚本或配置里扩展。

但是如果是做引擎,这些包装则是必须的了。
ps. 因为在团队里某部分代码可能会在时间线上由不同的人修改,尽早地提出一种明显的规则,可以约束后面的人不至于随意而为。如果一开始就在Player类里塞功能,早期可能没问题,不过随着项目进展,后面的人极有可能模仿前人的做法,最终就会导致不断地在Player里加功能代码。膨胀由此而来。  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 15:58 饭中淹

接着我在那边跟你说的,我是不允许代码和脚本碰数据对象的属性的。

属性必须由对象设计器生成。这个对象设计器是在线的,也就是运行时创建,更改的。

映射也是,映射说起来就是一种脚本,用来关联对象之间的属性的东西。


  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 16:06 Kevin Lynx

@饭中淹
话说你把你们的服务器整成全部配置驱动的;而我们在向全部脚本驱动靠近。  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 17:58 饭中淹

@Kevin Lynx
配置+脚本共同的
每个都可以实时修改
这样该错误,更新什么的,根本不用重启了

服务器本身的程序就是一堆底层的库在那里

然后就是支持这些数据对象和映射。

数据对象虽然看起来很复杂,实际上是个简单功能的容器类,和封包的结构很像。

大部分的事情都是在映射里做的。而这些映射都是脚本的。


脚本我准备用quartz composer那种卡片式的,这样可以用IPAD,GPAD,乐PAD等各种PAD,用3G卡在某个公园的角落里摸几下就把服务器BUG给修改好了。





  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 18:01 饭中淹

@Kevin Lynx
数据也脚本化,我感觉不合适。

我是要提供可视化编辑工具给策划,让他们自己去设计数据对象。

脚本这些粗活,就是服务器程序来做。

所有工具都做成各种PAD可部署的,这样就不用限制办公地点和时间了。

随时随地做事。

有个好的点子可以立即应用到实际的游戏服务中去。

  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 18:05 Kevin Lynx

@饭中淹
我们这回策划将编写大量脚本。瞬间在策划组掀起了学习Lua的热潮。整体架子的发展路线,和你说的差不多。程序这边仅提供底层功能实现。  回复  更多评论   

# re: MMO游戏对象属性设计[未登录] 2011-05-03 18:15 杨粼波

数据还是放到配置里面的好,比如csv,xml。
放脚本里面可以,但是编辑性不好啊。  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 19:37 Kevin Lynx

@杨粼波
这倒提醒我了。还真是不方便编辑。  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-03 23:20 cui

都是单线程的服务? 多线程的服务实时更新配置文件,需要加的互斥太多了  回复  更多评论   

# re: MMO游戏对象属性设计 2011-05-06 10:55

@Kevin Lynx
@饭中淹

配置驱动与脚本驱动,我更偏向配置驱动,脚本太灵活了,debug的难度很大,要求高,不宜开放出去。配置驱动配置死了点,但是安全稳定。写一个配置编辑器来控制错误相对比较简单。

赞同@饭中淹 “不允许代码和脚本碰数据对象的属性的”,不然实在是非常危险。对于脚本,应该再封装一层api。  回复  更多评论   

# re: MMO游戏对象属性设计 2012-02-08 17:41 阿飞

拜读中,继续学习!  回复  更多评论   


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理