新的工程模式 完整的数据集中式 1
数据集中式的想法一开始出现于《RUN》,当时RUN作为一个带有物理逻辑的休闲游戏,有很多对物理,动作模块的过程型数据进行累计,计算的得分逻辑,并且通过得分逻辑对UI和特效进行显示控制。一开始的时候,没有统一的设计方式,只是完全的根据游戏逻辑的需求,将不同的逻辑分成不能的控制单元,然后相互访问。这种交叉式访问的工程结构,导致数据离散在不同的文件中,一个数据可能会被重复记录多次,并且控制单元间相互耦合度很高,一个控制单元的修改和扩展,会导致很多其他单元需要跟着一起变动。鉴于上述问题,RUN 当时做了一次重构。重构的目的是剥离控制单元之间的耦合,解决数据和数据计算的重复问题。重构的方向是定义一个数据中心(data center)。统一保存逻辑数据。所有逻辑数据都拥有存取接口,并且对一部分特殊数据,采用链表方式保存,便于对这些数据的变化历史进行记录和相关逻辑(例如每做一次得分动作都记录在链表中,后面可以统计出Combo);数据中心本身只提供数据的存取和历史查询接口,不需对数据的来源和使用具体逻辑负责。数据中心之外有可以注册多个控制器,每个控制器负责一个相关完整的游戏业务逻辑。控制器负责修改数据中心的一部分数据,但不需要将数据的变化通知给其他关心的控制器。每个控制器都会定期的访问数据中心,看看自己关心的数据是否有变化,如果有的话,就根据这些变化执行相应的工作,并且将结果重新放回数据中心。
这样将系统逻辑拆分成多个相互独立的控制器后,逻辑模块的耦合度被大大降低了,一个模块的改动,通常不会影响到工程的其他部分。这种模型的缺点是当很多控制器对数据的访问频率很高,而控制器间数据的依赖程度不高的情况下,反而会降低整个工程的执行效率。
后来这个模型在制作《武林至尊》时没有被继承下来,主要是因为第一次涉及MMORPG类型的项目,无法在一开始预估出逻辑模块间的数据依赖程度,如果数据依赖非常高,将数据集中起来无疑比较好,如果依赖程度不够高,那么上述模型反而是一种过设计。因此《武林至尊》在初始设计的时候,采用了一种将消息集中的方式。结果类似于上图,不同的是,数据没有集中起来,而是放到了每个控制器的内部,便于快速访问。中心处集中的是由每个控制器抛出的消息。
控制器在启动时会在中心点注册自己关心的消息,当中心点有新的消息时,会根据注册信息派发给相应的控制器。
消息集中模型当然有自己的优缺点,但这不是本文想讨论的内容了,以后会专门针对这种设计来扩展一些想法。
《武林至尊》在制作到后期时,我又突然对数据集中模型开始关注起来,因为这个时候对于MMORPG这种工程有了新的认识。上面讲到的两种设计都是针对客户端如果架构的,但其实网络游戏中,服务器端扮演了一个更为重要的角色。通常在设计时,都习惯将服务器端和客户端分开在思考(很大程度上是由于一般情况下,是由两个人或者两个部门来分别开发的),但在这个项目中,由于对服务器和客户端在设计方面的全权把控,让我得到了很多宝贵的经验。其实在最开始设计消息集中模型的时候,考虑过将服务器端抽象成一个网络远端的控制器,将网络消息和客户端本地消息统一起来进行设计,但在实现过程中发现由于网络消息本数据量和数据复杂度和客户端消息之间有非常大的差异(试想一个Win32消息和一个玩家背包数据的区别),这种设计最终没有被付诸实现。但从数据交互的角度来看,服务器端和客户端的控制器之间的差异就没有那么明显了。例如我们考虑玩家背包数据的变化这样一个案例。
服务器端需要对玩家背包数据进行修改,然后将数据通过网络传输到客户端。客户端的逻辑模块(控制器)在得到数据后会对本地数据进行修改,然后UI模块(控制器)通过得到数据变化的通知,重新从客户端内存中取出数据,根据数据进行显示上的变化。在这个过程中,有3个模块对数据进行了修改和访问。让人感兴趣的是,如果忽略掉服务器和客户度是两个独立的进程,数据放在不同的物理内存中(当然正常情况下,也不在一台物理机器上)这个差异,我们可以认为是3个模块在对同一块数据进行修改和访问。
--待续