refactor(scene): 简化 ISceneRoot 接口并重构场景路由系统

- 简化 ISceneRoot 接口,移除路由逻辑和状态管理职责
  - 移除路由方法:ReplaceAsync, PushAsync, PopAsync, ClearAsync
  - 移除场景加载方法:LoadAsync, UnloadAsync
  - 移除状态属性:Current, Stack, IsTransitioning
  - 添加容器管理方法:AddScene, RemoveScene

- 重构 SceneRouterBase 实现
  - PushInternalAsync:使用 ISceneFactory.Create() 创建场景实例,通过 Root.AddScene() 添加到场景树
  - PopInternalAsync:使用 Root.RemoveScene() 从场景树移除场景
  - 保持正确的生命周期调用顺序

- 职责分离更清晰
  - ISceneRoot:仅负责场景树容器管理
  - ISceneFactory:负责场景实例创建
  - SceneRouterBase:负责路由逻辑和生命周期协调

- 与 UI 路由系统设计保持一致
This commit is contained in:
GeWuYou 2026-02-15 15:17:55 +08:00 committed by gewuyou
parent b054ee1c4a
commit 629c0a70a9
2 changed files with 19 additions and 68 deletions

View File

@ -14,74 +14,22 @@
namespace GFramework.Game.Abstractions.scene;
/// <summary>
/// 场景根接口,定义了场景管理系统的核心功能
/// 负责管理场景的生命周期、场景栈操作以及场景间的切换控制
/// 场景根接口,定义了场景树容器的基本操作
/// 职责单一:管理场景节点的添加和移除
/// </summary>
public interface ISceneRoot
{
/// <summary>
/// 获取当前活动的场景行为对象
/// 返回null表示当前没有活动场景
/// 向场景树添加场景节点
/// 此方法仅负责将场景添加到场景树中,不涉及场景的加载逻辑
/// </summary>
ISceneBehavior? Current { get; }
/// <param name="scene">要添加的场景行为实例。</param>
void AddScene(ISceneBehavior scene);
/// <summary>
/// 获取所有已加载场景的行为对象列表
/// 列表采用栈式结构索引0为栈底场景最后一个元素为当前活动场景
/// 从场景树移除场景节点
/// 此方法仅负责从场景树中移除场景,不涉及场景的卸载逻辑
/// </summary>
IReadOnlyList<ISceneBehavior> Stack { get; }
/// <summary>
/// 获取场景系统是否正在进行切换操作。
/// true表示正在执行场景加载、卸载或切换false表示系统空闲。
/// </summary>
bool IsTransitioning { get; }
/// <summary>
/// 异步替换当前场景,清空整个场景栈并加载新场景。
/// 此操作会卸载所有现有场景,然后加载指定的新场景。
/// </summary>
/// <param name="key">要加载的场景唯一标识符。</param>
/// <param name="param">可选的场景进入参数,用于传递初始化数据。</param>
/// <returns>表示替换操作完成的ValueTask。</returns>
ValueTask ReplaceAsync(string key, ISceneEnterParam? param = null);
/// <summary>
/// 异步压入新场景到场景栈顶部。
/// 当前场景会被暂停,新场景成为活动场景。
/// </summary>
/// <param name="key">要加载的场景唯一标识符。</param>
/// <param name="param">可选的场景进入参数,用于传递初始化数据。</param>
/// <returns>表示压入操作完成的ValueTask。</returns>
ValueTask PushAsync(string key, ISceneEnterParam? param = null);
/// <summary>
/// 异步弹出当前场景并恢复下一个场景。
/// 当前场景会被卸载,栈中的下一个场景变为活动场景。
/// </summary>
/// <returns>表示弹出操作完成的ValueTask。</returns>
ValueTask PopAsync();
/// <summary>
/// 异步清空所有已加载的场景。
/// 卸载场景栈中的所有场景,使系统回到无场景状态。
/// </summary>
/// <returns>表示清空操作完成的ValueTask。</returns>
ValueTask ClearAsync();
/// <summary>
/// 异步加载指定场景并返回场景行为实例。
/// 此方法仅加载场景资源但不激活场景,通常用于预加载或后台加载场景。
/// </summary>
/// <param name="sceneKey">要加载的场景唯一标识符。</param>
/// <returns>表示加载操作完成的ValueTask包含加载成功的场景行为对象。</returns>
ValueTask<ISceneBehavior> LoadAsync(string sceneKey);
/// <summary>
/// 异步卸载指定的场景行为实例。
/// 释放场景占用的资源并从系统中移除该场景实例。
/// </summary>
/// <param name="scene">要卸载的场景行为实例。</param>
/// <returns>表示卸载操作完成的ValueTask。</returns>
ValueTask UnloadAsync(ISceneBehavior scene);
/// <param name="scene">要移除的场景行为实例。</param>
void RemoveScene(ISceneBehavior scene);
}

View File

@ -222,7 +222,7 @@ public abstract class SceneRouterBase
/// <summary>
/// 内部推送场景实现方法。
/// 执行守卫检查、场景加载、暂停当前场景、压入栈等操作。
/// 执行守卫检查、场景创建、添加到场景树、加载资源、暂停当前场景、压入栈等操作。
/// </summary>
/// <param name="sceneKey">场景键名。</param>
/// <param name="param">场景进入参数。</param>
@ -244,8 +244,11 @@ public abstract class SceneRouterBase
return;
}
// 通过 Root 加载场景Root.LoadAsync 返回 ISceneBehavior
var scene = await Root!.LoadAsync(sceneKey);
// 通过 Factory 创建场景实例
var scene = _factory.Create(sceneKey);
// 添加到场景树
Root!.AddScene(scene);
// 加载资源
await scene.OnLoadAsync(param);
@ -297,7 +300,7 @@ public abstract class SceneRouterBase
/// <summary>
/// 内部弹出场景实现方法。
/// 执行守卫检查、退出场景、卸载资源、恢复下一个场景等操作。
/// 执行守卫检查、退出场景、卸载资源、从场景树移除、恢复下一个场景等操作。
/// </summary>
/// <returns>异步任务。</returns>
private async ValueTask PopInternalAsync()
@ -322,8 +325,8 @@ public abstract class SceneRouterBase
// 卸载资源
await top.OnUnloadAsync();
// 从场景树卸载
await Root!.UnloadAsync(top);
// 从场景树移除
Root!.RemoveScene(top);
// 恢复下一个场景
if (_stack.Count > 0)