前面已经完成了界面的创建、生成和打开。这一篇介绍如何使用 GameScene 和树形 SceneProcedure 管理主界面、背包等业务流程。
项目地址:
一、本篇目标
在 MainScene 中创建下面的流程结构:
bash
MainScene
├── MainSceneHome
│ └── MainSceneBag
└── MainSceneExit
进入 MainSceneHome 时显示主界面,进入它的子流程 MainSceneBag 时打开背包,返回后恢复主界面状态。
这里的返回关系由 SceneProcedure 管理,而不是在 LayoutManager 中维护一个全局 UI 返回栈。
二、注册场景流程
修改 MainScene.cs:
bash
using System;
public class MainScene : GameScene
{
public override void assignStartExitProcedure()
{
mStartProcedure = typeof(MainSceneHome);
mExitProcedure = typeof(MainSceneExit);
}
public override void createSceneProcedure()
{
addProcedure<MainSceneHome>();
addProcedure<MainSceneBag>(typeof(MainSceneHome));
addProcedure<MainSceneExit>();
}
}
其中:
bash
addProcedure<MainSceneHome>();
注册一个根流程。
bash
addProcedure<MainSceneBag>(typeof(MainSceneHome));
表示 MainSceneBag 是 MainSceneHome 的子流程。
三、创建主流程
创建 MainSceneHome.cs:
bash
public class MainSceneHome : SceneProcedure
{
protected override void onInit(SceneProcedure lastProcedure)
{
LT.LOAD<UIMain>();
}
protected override void onInitFromChild(SceneProcedure lastProcedure)
{
LT.SHOW<UIMain>();
}
protected override void onExitToChild(SceneProcedure nextProcedure)
{
LT.HIDE<UIMain>();
}
protected override void onExit(SceneProcedure nextProcedure)
{
LT.HIDE<UIMain>();
}
}
几个生命周期的用途如下:
bash
onInit 从其他流程第一次进入当前流程
onInitFromChild 从自己的子流程返回
onExitToChild 进入自己的子流程
onExit 离开当前流程,且目标不是自己的子流程
当进入背包时,MainSceneHome 不会被完全退出,只会执行 onExitToChild。
从背包返回以后,则执行 onInitFromChild。
四、创建背包子流程
创建 MainSceneBag.cs:
bash
public class MainSceneBag : SceneProcedure
{
protected override void onInit(SceneProcedure lastProcedure)
{
LT.LOAD<UIBag>();
}
protected override void onExit(SceneProcedure nextProcedure)
{
LT.HIDE<UIBag>();
}
}
MainSceneBag 只关心背包界面。
它不需要处理主界面,也不需要知道主界面应该如何恢复,这些逻辑由父流程 MainSceneHome 自己负责。
这就是树形流程的主要作用:
bash
父流程管理父流程的界面
子流程管理子流程的界面
每个流程只处理自己的状态
五、从主界面进入背包
在 UIMain 中增加背包按钮:
bash
protected myUGUIImageSimple mBagButton;
节点绑定和点击注册可以由 UGUIGenerator 自动生成:
bash
newObject(out mBagButton, "BagButton");
mBagButton.registeColliderImage(onBagButtonClick);
点击后切换到背包流程:
bash
protected void onBagButtonClick()
{
mGameSceneManager.getCurScene().changeProcedure<MainSceneBag>();
}
执行流程如下:
bash
MainSceneHome
↓ onExitToChild
MainSceneBag
↓ onInit
打开 UIBag
六、从背包返回主界面
在 UIBag 的返回按钮中切换回父流程:
bash
protected void onBackButtonClick()
{
FrameUtility.changeProcedure<MainSceneHome>();
}
切换时:
bash
MainSceneBag
↓ onExit
MainSceneHome
↓ onInitFromChild
恢复 UIMain
也可以使用场景记录的上一个流程:
bash
protected void onBackButtonClick()
{
FrameUtility.backToLastProcedure();
}
明确知道目标流程时,直接调用 changeProcedure<T>() 会更清楚;通用返回按钮则可以使用 backToLastProcedure()。
七、为什么使用树形流程
如果背包、商城、任务都属于主界面的子功能,可以这样注册:
bash
public override void createSceneProcedure()
{
addProcedure<MainSceneHome>();
addProcedure<MainSceneBag>(typeof(MainSceneHome));
addProcedure<MainSceneShop>(typeof(MainSceneHome));
addProcedure<MainSceneTask>(typeof(MainSceneHome));
addProcedure<MainSceneExit>();
}
结构如下:
bash
MainSceneHome
├── MainSceneBag
├── MainSceneShop
└── MainSceneTask
进入任意子流程时,父流程统一执行:
bash
protected override void onExitToChild(SceneProcedure nextProcedure)
{
LT.HIDE<UIMain>();
}
从任意子流程返回时,父流程统一执行:
bash
protected override void onInitFromChild(SceneProcedure lastProcedure)
{
LT.SHOW<UIMain>();
}
不需要在背包、商城和任务流程里分别处理主界面。
八、父流程和子流程都会更新
当前处于子流程时,框架会先更新父流程,再更新子流程:
bash
MainSceneHome.onUpdate
↓
MainSceneBag.onUpdate
因此可以把多个子流程都需要的公共逻辑放在父流程中:
bash
public class MainSceneHome : SceneProcedure
{
protected override void onUpdate(float elapsedTime)
{
// 主城公共更新逻辑
}
}
背包流程只处理背包自己的更新:
bash
public class MainSceneBag : SceneProcedure
{
protected override void onUpdate(float elapsedTime)
{
// 背包流程更新逻辑
}
}
没有持续更新需求时,不需要重写 onUpdate。
九、场景退出流程
MainSceneExit 一般用于统一清理当前场景资源:
bash
public class MainSceneExit : SceneProcedure
{
protected override void onInit(SceneProcedure lastProcedure)
{
}
protected override void onExit(SceneProcedure nextProcedure)
{
genericExit(0);
}
}
genericExit 会卸载当前场景中的局部界面。
需要按资源标签清理特效和 Prefab 时,可以传入有效标签:
bash
genericExit(MAIN_SCENE_RESOURCE_TAG);
十、职责划分
建议保持下面的分工:
bash
GameScene 注册流程并指定入口、出口流程
SceneProcedure 管理当前业务状态和所属界面
LayoutScript 处理界面显示与交互
LayoutManager 管理界面的加载、显示、隐藏和卸载
不要让 LayoutManager 决定背包应该返回哪里。
返回目标属于业务流程,应该由 SceneProcedure 决定。
十一、总结
使用场景流程的基本步骤是:
树形 SceneProcedure 可以让每个流程只关心自己的界面和状态,避免所有页面切换逻辑都集中到一个全局 UI 管理器中。