我们这次整理阶段准备了好久,终于可以进入学习阶段了。 先列出 Manager Of Managers 如下:
-
MainManager: 作为入口管理器。
-
EventManager: 消息管理。
-
GUIManager: 图形视图管理。
-
AudioManager: 音效管理。
-
PoolManager: GameObject管理(减少动态开辟内存消耗,减少GC)。
-
LevelManager: 关卡管理。
-
GameManager: 游戏管理。
-
SaveManager: 配置&存储管理。
-
MenuManager 菜单管理。
我们今天来实现第一个,MainManager,入口管理器。
什么是入口管理器?
字如其意,就是用来管理入口的。
既然称得上是管理,那么我们的项目肯定是有多个入口的,除了有多个入口之外呢,入口处也有可能有多个流程,比如资源加载流程、第三方 SDK 启动流程、热更新检测等等,都是在入口处完成的。
到这里,我们要解决的问题,也就是 MainManager 的职责有点眉目了:
-
管理多个入口。
-
负责游戏的启动流程。
第二个问题我们可以理解,但是第一个问题,为什么会有多个入口需要管理?
为什么需要多个入口?
我们在一开始做项目的时候,每次改一点点代码(或者不止一点点),要看更改的结果就要启动游戏-> Loading 界面 -> 点击各种按钮 ->跳转到目标界面等,经过一系列的操作才能看到更改的结果,或者 Log 之类的。这样非常浪费时间的,如果每天按照需要 10 次这种行为,就会浪费很多时间,如果按照时薪算的话,那就是……很多钱。
流程图是这样的:
为什么会出现这种问题呢?
-
模块间的耦合度太高了。下一个模块要依赖前一个模块的一些数据或者逻辑。
-
或者有可能是这个模块设计得太大了,界面太多,也会发生这种情况。
解决方案
针对问题 1:在模块的入口提供一个测试接口,用来写这个模块的资源加载或者数据初始化的逻辑。 针对问题 2:在模块的入口提供一个测试接口,写跳转到目标界面的相关代码。 流程图是这样的: 虽然很简单,但是解决了问题。
阶段的划分
资源加载乱七八糟的代码和最好能一步跳转到目标界面的代码,需要在出包或者跑完整游戏流程的时候失效。 如何做到? 答案就是阶段的划分。 我们的框架里分为如下几个阶段:
-
开发阶段:不断地编码->验证结果->编码->验证结果->…….
-
出包/真机阶段:这个阶段主要是跑完整流程,在真机上跑跑,给 QA 测测。
-
发布阶段:上线。
对应的枚举:
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
更多内容
-
QFramework 地址: https://github.com/liangxiegame/QFramework
-
QQ 交流群: 623597263
-
Unity 进阶小班 :
-
主要训练内容:
-
框架搭建训练(第一年)
-
跟着案例学 Shader(第一年)
-
副业的孵化(第二年、第三年)
-
权益、授课形式等具体详情请查看 《小班产品手册》 :https://liangxiegame.com/master/intro
-
关注公众号:liangxiegame 获取第一时间更新通知及更多的免费内容。
1万+

被折叠的 条评论
为什么被折叠?



