Unity MyFramework 用法说明(五):使用 GameScene 和 SceneProcedure 管理业务流程

前面已经完成了界面的创建、生成和打开。这一篇介绍如何使用 GameScene 和树形 SceneProcedure 管理主界面、背包等业务流程。

项目地址:

github.com/ZHOURUIH/My...

一、本篇目标

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));

表示 MainSceneBagMainSceneHome 的子流程。


三、创建主流程

创建 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 管理器中。

相关推荐
_zhourui_h_7 小时前
Unity MyFramework 用法说明(四):使用 UGUIGenerator 自动生成 UI 代码
unity3d
SmalBox1 天前
【节点】[EvaluateFoamData节点]原理解析与实际应用
unity3d·游戏开发·图形学
_ZHOURUI_H_1 天前
MyFramework: 同样是 Unity 游戏开发框架,和 HTFramework 的设计取向有什么不同?(下)
unity·游戏引擎·游戏开发·游戏ui·手游开发
SmalBox2 天前
【节点】[ComputeVertexPosition节点]原理解析与实际应用
unity3d·游戏开发·图形学
孟无岐2 天前
LayaAir IDE 插件开发入门:用 TypeScript 给编辑器加一个自己的面板
typescript·游戏开发·工程化·编辑器扩展·layaair·ide 插件
SmalBox3 天前
【节点】[ScleraUVLocation节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox4 天前
【节点】[ScleraLimbalRing节点]原理解析与实际应用
unity3d·游戏开发·图形学
UWA4 天前
资源回收“两头堵”:RUUA调了会卡,不调内存又涨
性能优化·memory·游戏开发
qiqizizzz5 天前
Unity层级问题 #03 | MeshRender vs UI 组件
unity3d·游戏开发