Unity 游戏框架搭建: MainManager

我们这次整理阶段准备了好久,终于可以进入学习阶段了。 先列出 Manager Of Managers 如下:
  • MainManager: 作为入口管理器。
  • EventManager: 消息管理。
  • GUIManager: 图形视图管理。
  • AudioManager: 音效管理。
  • PoolManager: GameObject管理(减少动态开辟内存消耗,减少GC)。
  • LevelManager: 关卡管理。
  • GameManager: 游戏管理。
  • SaveManager: 配置&存储管理。
  • MenuManager 菜单管理。
我们今天来实现第一个,MainManager,入口管理器。

什么是入口管理器?

字如其意,就是用来管理入口的。
既然称得上是管理,那么我们的项目肯定是有多个入口的,除了有多个入口之外呢,入口处也有可能有多个流程,比如资源加载流程、第三方 SDK 启动流程、热更新检测等等,都是在入口处完成的。
到这里,我们要解决的问题,也就是 MainManager 的职责有点眉目了:
  1. 管理多个入口。
  2. 负责游戏的启动流程。
第二个问题我们可以理解,但是第一个问题,为什么会有多个入口需要管理?

为什么需要多个入口?

我们在一开始做项目的时候,每次改一点点代码(或者不止一点点),要看更改的结果就要启动游戏-> Loading 界面 -> 点击各种按钮 ->跳转到目标界面等,经过一系列的操作才能看到更改的结果,或者 Log 之类的。这样非常浪费时间的,如果每天按照需要 10 次这种行为,就会浪费很多时间,如果按照时薪算的话,那就是……很多钱。
流程图是这样的:

为什么会出现这种问题呢?

  1. 模块间的耦合度太高了。下一个模块要依赖前一个模块的一些数据或者逻辑。
  2. 或者有可能是这个模块设计得太大了,界面太多,也会发生这种情况。

解决方案

针对问题 1:在模块的入口提供一个测试接口,用来写这个模块的资源加载或者数据初始化的逻辑。 针对问题 2:在模块的入口提供一个测试接口,写跳转到目标界面的相关代码。 流程图是这样的: 虽然很简单,但是解决了问题。

阶段的划分

资源加载乱七八糟的代码和最好能一步跳转到目标界面的代码,需要在出包或者跑完整游戏流程的时候失效。 如何做到? 答案就是阶段的划分。 我们的框架里分为如下几个阶段:
  1. 开发阶段:不断地编码->验证结果->编码->验证结果->…….
  2. 出包/真机阶段:这个阶段主要是跑完整流程,在真机上跑跑,给 QA 测测。
  3. 发布阶段:上线。
对应的枚举:
    
public enum EnvironmentMode { Developing , QA , Release }
很明显,乱七八糟的代码是要在开发阶段是有效的,但是在 QA 或者 Release 版本中无效的。那么只要在游戏的入口处判断当前在什么阶段就好了。
代码如下:
    
using UnityEngine ; namespace QFramework { public enum EnvironmentMode { Developing , Test , Production } public class MainManager : MonoBehaviour { public EnvironmentMode Mode ; // Use this for initialization void Start ( ) { if ( Mode == EnvironmentMode . Developing ) { // 测试逻辑 } else { // 正常逻辑 } } } }
可以看到在 Start 方法里对 Mode 进行了判断。不过如果这样去写的话我们的 MainManager 就会在别的项目中不能复用,因为 MainManager 作为 Manager Of Managers 之一,它不能在代码本身写项目有关的逻辑,因为它是框架层的脚本。
那要怎么办呢?答案是通过继承。
如何通过继承搞定? 我们看代码就知道了,代码如下:
    
using UnityEngine ; namespace QFramework { public enum EnvironmentMode { Developing , Test , Production } public abstract class MainManager : MonoBehaviour { public EnvironmentMode Mode ; private void Start ( ) { switch ( Mode ) { case EnvironmentMode . Developing : LaunchInDevelopingMode ( ) ; break ; case EnvironmentMode . Test : LaunchInTestMode ( ) ; break ; case EnvironmentMode . Production : LaunchInProductionMode ( ) ; break ; } } protected abstract void LaunchInDevelopingMode ( ) ; protected abstract void LaunchInProductionMode ( ) ; protected abstract void LaunchInTestMode ( ) ; } }
首先我们的 MainManager 变成了一个抽象类,也就是说,不希望大家直接用。而是通过继承去使用。当然这个类本身问题很多,不过我们可以通过做一些小示例来发现问题并解决。
到这里,这个类呢,可以满足我们的切换入口的问题,当然呢,也支持了几种阶段。那么我们接下来,开始写小示例。

第十一个示例

我们来先创建两个场景,并创建两个脚本,GameModule 和 HomeModule 如下图所示:
GameModule 脚本如下: Assets/QFramework/Example/11.MainManager/Game/GameModule.cs
    
using QFramework ; using UnityEngine . SceneManagement ; namespace Game { public class GameModule : MainManager { public static void LoadModule ( ) { SceneManager . LoadScene ( "Game" ) ; } protected override void LaunchInDevelopingMode ( ) { // 开发逻辑 } protected override void LaunchInTestMode ( ) { // 正常的 测试逻辑 } protected override void LaunchInProductionMode ( ) { // 正常的 生产逻辑 } } }
大家注意,它的命名空间是 Game,说明它是某个游戏里实现的。GameModule,意思就是游戏模块,GameModule 则作为游戏模块的入口。
HomeModule 脚本如下: Assets/QFramework/Example/11.MainManager/Home/HomeModule.cs
    
using QFramework ; namespace Game { public class HomeModule : MainManager { protected override void LaunchInDevelopingMode ( ) { // 开发逻辑 } protected override void LaunchInTestMode ( ) { // 测试逻辑 // 加载资源 // 初始化 SDK // 点击开始游戏 GameModule . LoadModule ( ) ; } protected override void LaunchInProductionMode ( ) { // 生产逻辑 // 加载资源 // 初始化 SDK // 点击开始游戏 GameModule . LoadModule ( ) ; } } }
HomeModule,同理,是主页模块,而主页一般有大量的 UI 逻辑,当然,按照一般的流程来看,玩家要先进入 Home 模块,才能进入 Game 模块。而这部分的逻辑呢,我们已经在以上代码中的 TestMode 和 ProductionMode 的方法里已经实现了。当然在真实项目中不可能这么简单,往往模块跳转的逻辑不可能写在 HomeModule 里,但是大体流程是如此的。
我们把这个 HomeModule 挂在了,Home 场景的一个空的 GameObject 上,如下图所示:
同样 Game 场景也做同样的操作: 完成之后,我们再切换回 Home 场景。
我们看到,默认的 Mode 是 Developing 模式,我们通过 Inspector 把它改成 Production 模式,更改后如下图所示: 然后我们确保,Build Setting 中已经包含 Home 和 Game 场景: 之后,运行这个场景。
运行之后,很快切换到了 Game 场景:
OK,这就算是我们完整的游戏流程。从 Home->Game 模块,非常简单。
游戏一开始是进入 Home 模块的,而正常流程下,Home 会做一些 加载资源 和 SDK 初始化等操作。 那么假如我们要在 Game 模块改一点东西呢? 我们直接打开 Game 场景。
它默认是 Developing Mode,刚好我们需要这个模式。那么 Game 在正常流程下,Game 不会加载资源、初始化 SDK 等,因为这部分逻辑 Home 模块已经做完了,而正常流程下,Game 场景是由 Home 模块打开的。
但是呢,现在我们想直接打开 Game 场景,并且当他运行后,也能进行测试。那么只要把 GameModule 的代码改成如下就好了:
    
using QFramework ; using UnityEngine . SceneManagement ; namespace Game { public class GameModule : MainManager { public static void LoadModule ( ) { SceneManager . LoadScene ( "Game" ) ; } protected override void LaunchInDevelopingMode ( ) { // 开发逻辑 // 加载资源 // 初始化 SDK // Game 的一些准备逻辑 (角色选择、准备一些假的数据等等) } protected override void LaunchInTestMode ( ) { // 正常的 生产逻辑 } protected override void LaunchInProductionMode ( ) { // 正常的 生产逻辑 } } }
大家注意看 LaunchInDevelopingMode 中的注释,这样,我么那就可以做到在开发模式下,只要打开 Game 场景就可以直接验证结果了。
我们再看一下之前的流程图是不是我们要完成的逻辑。 是我们要完成的逻辑。
那么我们的 MainManager 的第一个使命,就算完成了,就是管理多个入口,但是本身还是有一些问题的,我们在下一篇进行解决。
今天的内容就这些我们下一篇再见,拜拜~
转载请注明地址:凉鞋的笔记: liangxiegame.com

更多内容

  • QQ 交流群: 623597263
  • Unity 进阶小班 :
  • 主要训练内容:
  • 框架搭建训练(第一年)
  • 跟着案例学 Shader(第一年)
  • 副业的孵化(第二年、第三年)
  • 权益、授课形式等具体详情请查看 《小班产品手册》 :https://liangxiegame.com/master/intro
  • 关注公众号:liangxiegame 获取第一时间更新通知及更多的免费内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值