在以往的游戏开发中,我们往往需要处理很多角色,围绕着这些角色的组织形式,解耦等话题,出现了很多复合设计模式。例如:pureMVC,MVVM ,MVC 等等。对于这些设计模式,都是有利有弊,有他自己的使用场景。不过我们要透过表象看本质,就需要抛开这些设计模式,分析游戏中的各种角色,以及他们的相互作用关系。才能最终找到一种属于自己的使用模式。
一 数据
1. 数据的分类
数据是游戏中不可或缺的部分,比如单机游戏的本地存档数据,网络游戏从服务器获取的远程存档数据,这两种统称为存档数据;再有就是配置表数据,常量数据等等。不管你是什么数据,这里我统统称之为数据。 形如:
2. 数据的获取方式
数据的获取方式由数据的存放位置决定,如果存放在服务器,需要通过网络接口完成存取,如果存在本地,需要调用本地存取接口完成。如果是配置文件,那需要自己加载后管理。这些操作都可以封装在对应的管理器中实现统一的接口提供外部使用。 关于这部分的文章可以参考:一个可屏蔽长短链接的网络模块
3. 数据的管理
对于存档数据,如果是用户数据,会常驻内存,可以存放在一个单例中。如果是某个模块单独的数据,可以由各个模块的数据管理器自己管理。配置数据自然是通过配置数据的读取管理器统一调用。
我个人的习惯是将这些数据整理好之后再通过数据管理器提供给界面使用。整理后的结构大多是一个树状结构。数据管理器是一个模块的根模型。
二 显示
作用:
- 显示数据
- 管理子View(Item),Item的数量小于等于Model的数量,重复利用。
- 监听本模块的数据管理器和控制器的事件通知,更新界面。
- 结合状态机处理复杂的游戏显示:
角色的状态管理,移动,跑,跳,攻击。 战斗状态:战斗开始,战斗中,战斗结束。
三 控制器
作用:
- 调用UI管理器 弹出界面
- 与服务器交互,更新存档数据。
- 继承事件派发器,派发局部事件,触发本模块的UI更新数据。
四 UI管理
UI管理顾名思义,管理ui的弹出和关闭;这里的ui是各种弹窗的统称,不管是几级界面,也不管你是tip还是toast。都归于一个ui管理器管理。
- UI管理器分层:层级越高的ui会显示在游戏的最上方。
- UI管理器的类型:队列类型,栈类型,单例类型。
例如: 一级界面属于第一层,类型是单例类型,也就是进入一个移除一个,同时只能存在一个UI。 弹窗界面属于第二层,类型是占类型,后进先出、 活动界面属于第三层,在弹窗之上,使用队列类型,关闭一个弹出一个。先进先出。 tip 属于第四层,使用栈类型。 toast 属于第五层 使用栈类型。 注意层级越高的ui会遮挡底层级的UI。 详细内容可阅读:游戏开发之UI管理器
五 事件
事件是模块内部,模块与模块之间进行通信的主要手段。 事件种类:
- 全局事件: 整个游戏有一个全局事件管理器,管理整个游戏的全局事件。派发的全局事件在哪里都可以监听的到。
- 局部事件: 各个模块的控制器和数据管理器乃至数据本身派发的事件。
六 模块
针对模块开发,不仅可以使项目的目录结构清晰,而且对新人也比较友好。当模块与模块之间通信时遵循几个原则
- 每个模块都有一个或多个控制器,一个数据管理器和若干个View。
- 控制器调用控制器
- 数据管理器调用数据管理器
- 模块之间的View无通信
- 模块内的View之间通过事件通知通信。
- 每个模块定义自己的事件名称,由于是局部派发,所以即使与其他模块定义的名称相同也无妨。
- 模块之间越透明越好。达到高内聚低耦合的目的。减少版本管理的冲突几率。
七 结语
在我看来,游戏中最重要的角色为以上几种。对于一些设计模式给成的Command,Mediator,Proxy之类的。我感觉没有必要。我的原则是涉及的角色尽量少,然后也能够达到解耦的目的就好。比如控制器调用UIManager弹出界面这件事情,是可以写一个中介者来管理所有的UI。但是对于体量不大的游戏其实没那个必要,所以也就不是必须的存在。如果非要给我这种使用方式向某个设计模式上靠的话,我感觉更像是MVVM。存档数据和配置数据为模型,数据为ViewModel;View都是通过使用ViewModel组织好的数据,完成各种需求。不推荐使用PureMVC。
|