我们可以用以上的方法来试着架构Unity3D项目,我们用分层的思维方式,先确定架构的层级,如下图。
把整个项目分成五大层级,网络层,数据层,资源层,核心逻辑框架层,UI层。
这样一分清晰的知道了我们需要做哪几块大类的东西。但是这样拆分太笼统,特别是核心逻辑框架这块,完全是概括性的层级,无法表达具体的系统。所以我们再拆分层级。把太过于笼统的层级进行再分层。如下图:
经过再分层后,把核心逻辑框架分成了,工具编辑器,角色行为框架,AI框架,地图场景与寻路框架,Shader与特效,设备原始接口。这些子层都是在核心逻辑层中,他们有自己的框架,也可以互相调用,构成了核心逻辑部分,也就是核心玩法或者说核心战斗的主要部分。
我们将资源管理层和数据管理层再进行了拆分,分成了Assetbundle资源管理和Prefab资源管理,以及内存数据管理和外部数据管理,这样更清晰的分工了各层的职能。其实还有很多其他的层级我们这里没有提到的,包括常用库,工具库,动画控制等,这里暂不一一提出来。
在游戏项目中最常用的是,数据表,网络层,UI层,常用库,这几个模块。我们可以用这个层级的方式来试着搭建一个完整的项目,只是做抽象上的编写,就可以清晰的知道,这个项目需要哪些模块和层级了。
比如如果项目单机的策略类游戏,可能就没有很多角色上的东西,而多了很多2D动画行为控制上的需求。这时我们就可以把层级划分下,把注意力重点放在,2D动画行为控制,UI框架,数据管理,资源管理,以及AI上。
如果我们项目是3D人物角色为主的网络游戏,就有地形地图,角色行为控制,还需要一套角色技能特效动画编辑器。这时我们就需要把网络层这块好好决策下该用哪种框架,TCP-Socket?UDP?还是web形式的HTTP?!3DMMRPG的难度主要集中在了角色技能动画、AI、地图、物理模拟上。我们可以重点划分出来,找人专门做这块,把最难把控的放在最优先的位置去做,而后再对这些层级进行细致化的构建。
对模块进行细致化构建时,我们可以用分治法方法去构建。如果某个要解决的内容已经确定了,而这个内容或问题的规模还是太大,无法直接的下手解决,那么我们用分治的方法,把一个问题分成几个小问题来做,把小问题再划分成更小的问题直到小到能直接解决,再依次对他们跟进处理。
这里我们拿网络层来说,进行分而治之,如下图:
图中我们把网络层拆分成http,tcp-socket,udp这三种类型的形式,再对每个类型的具体接口进行了拆分,对于拆分出来的每个接口,如果还不能直接使用再进行细致的拆分,直到拆分到可以具体实施了为止。在上图中,我们以接口的形式进行拆分,先将接口拆分成,连接,断开连接,发送数据,收到数据,以及(断开、连接、终结)网络事件,然后再对每个接口进行拆分,把接口需要处理的问题拆分出来各个击破。
除了我们举例的网络层,其他层级部分的框架也可以用同样的方式进行类似的分解,用分而治之的方法逐个击破每个模块。这里我们描述了各个模块的拆分原则:
数据表 -- XLS导为二进制文件还是Json或其他格式,读取接口和解析接口的定义。
UI层 -- 使用NGUI还是UGUI,界面基类,界面管理,输入事件封装,自定义通用组件基类,自定义各类通用组件。
外部资源管理 -— 是否使用AssetBundle,AssetBundle资源分类,AssetBundle资源间的依赖关系,加载与释放AssetBundle的管理,AssetBundle加密。
AI层 -— 使用状态机还是行为树或者其他,状态机或行为树接口实现,AI可视化工具,AI扩展接口。
地形地图 -— 地图是2D还是3D,场景编辑器的结构,是否需要Mesh合并,场景内的大小物件区别对待,大地形在游戏里该怎么逐步显示,是否要划分区块。
寻路与网格 -— 使用A星还是跳点算法或者其他,使用网格栅格还是三角网格,长距离寻路的解决方案,地图数据管理。
常用库 -— 时间函数,数学函数,数字变量加密封装,坐标转换函数,Debug调试工具,各大逻辑系统通用工具等等。
角色行为控制 -— 人物移动处理方案,摄像机的碰撞检测,动画特效编辑器,技能编辑器,行为流的建立。
2D动画控制 -— 动画组件封装,2D动画的制作流程,2D图合并为图集。
实际工作中,我们对层级和模块逐个攻破的同时,也进入架构演化模式。一开始的做的架构中某个部位的并不适合,或需要改善,在后面的工作中,修复和完善架构是演化的重要步骤。
在不断编写完善架构的过程中原本抽象简单的架构,开始复杂化。虽然每个模块都在有条不紊的进行中,但也会不断冒出各种各样不适应或者不符合实际需求的问题出现,我们需要及时跟进演化内容。去除、重构或者改善,前面由于各种原因而导致的错误的理解。
最后架构设计的文档要及时跟进完善,在抽象的过程中,我们需要整理和记录整个过程,以便为今后在完善时能够一下子翻阅到并记起当时在架构时所考虑的各方面问题的原因。