|
|
架构设计.txt
时间系统:MessageRouter
空间系统:Scene及其派生类
时空之中所容纳的对象(游戏世界这个模型的基本单位):Object及其派生类
时空之中对象间的交互:Message及其派生类
(以下用“Scene”来代表“Scene及其派生类”,用“Message”代表“Message及其派生类”,用“Object”代表“Object及其派生类”)
Scene容纳了所有的游戏对象,构成了整个游戏世界。
Object间的交互有两种:一种是直接调用目标Object的成员函数,另一种是向目标Object发送一个Message。
Object里只有与该对象交互的基本接口,或者说,对于一个函数,只有当它的参数只和这一个对象有关时,才能成为这个对象的成员函数,也就是说Object的成员函数的参数只会涉及到该函数所在的对象而不会涉及到其他对象,因此像技能之类的要涉及到两个或更多对象的操作不能作为成员函数实现。另外可能经常会产生变化的那些操作也不应该作为成员函数来实现,比如技能、魔法等对象间交互就不应该作为成员函数实现。
Message里除了该消息所需要携带的信息(数据成员)之外,还会有一个统一的接口以及相关的行为。该Message是自我解析的,也就是说当这个Message需要被解析时(或者说被应用于相关对象时)外界只是调用该Message的一个统一的函数接口并传入相关的对象,然后由该Message的成员函数来自我解析。Message是用来实现对象间的交互的,或者说是用来实现那些涉及两个或多个对象的行为的,因此上文所说的那些不应该作为Object的成员函数实现的行为可以用Message来实现。Message的那个自我解析的函数里包含了对象间交互的行为内容,可以是调用相关对象的成员函数(也就是上文所说的那些基本接口),也可以是直接操作相关对象的数据成员。Message可以通过对象的基本函数接口来传递给目标对象,也可以先传递给MessageRouter,由MessageRouter在指定的时间转交,正是因为MessageRouter的这个定时传递Message的功能所以才把MessageRouter看作时间系统的主要部分。
将对象间的交互行为从对象中分离出来,变成独立于Object的Message,这样做的好处主要在于灵活性。考虑如下方案:
所有的Object类都保存在一个Object.so动态链接库里,在系统运行时动态载入其中的Object类,而所有的Message类都保存在一个Message.so动态链接库里,也是在系统运行时动态载入其中的Message类。如果要向正在运行的系统之中添加对象间的交互类型(比如添加魔法或技能),这时如果这些交互是在Object类中用成员函数实现的那么就需要把涉及到的所有的Object的实例都使用新的类重建一遍;而如果这些新增的行为是作为Message实现的,那么现有的一切都不需要变动,只需要载入新增的那些Message类就可以了,当然,客户端也需要动态载入那些新的Message类。这里的Message其实就是Command模式中的Command。
另外,如果允许客户端的用户使用系统提供的那些Message来进行有序组合,组成一个新的Message,那么就可以实现由客户端用户在运行的时候定制Message而且不需要编程。这里“有序组合”的含义是:将各个Message对象组成一个有向图,有一个入口和若干个出口,从入口Message开始执行,遇到分叉时根据指定的条件进行路径选择,一直运行到出口Message后停止。这样系统只需要提供相对较少的Message,以及一些必要的组合的限制条件,就可以提供非常丰富的对象间交互。需要注意的有三点:一是如果提供的Message以及限制条件设计的不好,那么可能会使得系统非常的不平衡,使得绝大多数的组合都没有意义,结果还是会使系统很单调;二是由于Message组成的有向图可能构成死循环,因此需要一定的机制来防止死循环Message图的产生,以及检测死循环并进行干涉的机制;三是可能有些Message图会使得系统负担非常重,所以需要机制来应对这个问题以使系统可以正常地持续运行下去。
每个客户端中的Scene都是服务器上的Scene的一个子集,客户端的Scene中的Object,如果它对应了服务器上的某个Object的话,那么其实它是服务器上对应Object的Proxy,只是客户端上针对这些Proxy的交互的效果可以等价于针对服务器上的Object的交互,另一方面客户端里的Object可以分为两部分,一部分负责客户端本地事务,比如动画以及详细的碰撞检测这些,另一部分则负责把需要传递给服务器的交互传递给服务器,而后者这部分才是严格意义上的Proxy。所以客户端的Object类与服务器端的Object类并不完全相同,不过至少对外的函数接口是相同的,而数据成员和各个函数的实现则会有所不同,而且客户端的Object会包含一个指向所代理对象的Proxy。
设计中的类与ICE的Slice的概念的对应关系:
ServerObject: SliceInterface + CppImplementation
ClientObject: SliceClass + SliceReference
Message: SliceClass
TODO:
1.Message中from和to的实现和解析。
Thinking:
1.1考虑到目前网游的模式,可以认为虽然有些交互是由客户端发起的,但是这些交互并不是客户端上某个对象与服务器中某个对象的交互,而仍然是服务器中的对象间交互,也就是说并不存在跨网络的对象间交互(这里特指使用Message进行的对象间交互)。所以可以考虑这样的方案:
客户端生成Message时,可以不填写from,然后发送时通过RPC机制调用Object的统一接口,把Message传递给那个对应了from的Object,然后由那个接收的Object来填写from,这样剩下的问题就是如何实现和解析to。客户端通过RPC把Message交给from对象而不是直接交给to对象的好处主要是可以防范伪造from信息。例如玩家要攻击某个怪物时,生产的攻击Message通过RPC发送给服务器中玩家所控制的角色Object,由该角色Object来转交给被攻击的的怪物Object。
功能组织.txt
- MMORPG所需的特性:
- 时间系统:
- 相对定时/绝对定时
- 循环定时
- 相对计时/绝对计时
- 空间系统:
- 空间游览
- 空间划分/管理
- 座标系统
- 寻径系统
- 碰撞检测
- 时空系统(时间系统+空间系统):
- 物理模拟:
- 运动模拟
- 碰撞响应
- 时空中的对象:
- 对象维持:
- 状态维持与管理
- 对象行为/对象交互:
- 主动行为
- 被动行为
- 行为决策/AI/行为控制
- 对象状态:
- 内部状态(自身状态)
- 外部状态(对象间的联系)
- 这些组件可以根据需要而启用或停用,可以互相组合以及给出相关参数,可以在组件上挂上定制的代码或行为。
- “状态维持”说明状态本身也是可以有主动行为的。
- 时空中的对象,虽然直观上可以分成物品和角色这两大类,但是实际上,它们是相同的,所以物品也可以具有角色所能具有的任何特性。
复制代码
真实感问题.txt
游戏要有真实感才能让玩家有比较好的沉浸感,同时真实感强意味着更容易上手,门槛低。一个游戏的真实感取决于其中存在的规则和规律。如果一个游戏把现实世界的一切规则和规律都实现了,并且没有其他更多的规律,那么这就是个很好的虚拟现实。那么如果把这样的游戏里的规则和规律精简一下,这样现实中的某些束缚或限制就不会在游戏中出现,这样可以给游戏提供更大的灵活度,但是真实感会有所降低。如果在现实规则的基础之上还增加了其他(现实中不存在的)规则,这样游戏里的束缚会比显示中还要大,真实感也会减小。
游戏既要有真实感,也要有灵活度,这样才能表现出一个现实中没有却很有真实感的游戏世界。因此可以考虑对现实中的规则或规律进行分层,底层的规则保证了真实感,而有选择地放弃某些上层规则则可以给游戏带来灵活度,增加更多可能。
[em10] |
|