跳到主要内容
版本:v3

GSIManagerBase

重要 注意 提醒

Coding Style wiki


GSIManagerBase<T>GSIFrame(Game Stage Integration)的游戏阶段管理器抽象基类(FSM 概念),统一管理 GSIBase 阶段的注册、查询、切换与更新驱动。继承后即可通过静态 Default API 直接以子类类名操作,通常一个游戏只需要一个管理器子类。

命名空间OxGFrame.GSIFrame
类型public abstract class
源码GSIManagerBase.cs
using OxGFrame.GSIFrame;

提醒 若项目有热更新工程,建议区分两个管理器分别管理(如 AotGameStageManagerHotfixGameStageManager)。

声明

public abstract class GSIManagerBase<T> where T : GSIManagerBase<T>, new()

泛型参数

泛型参数说明
T管理器子类自身类型(CRTP 自我引用约束),需具备无参构造函数(new())。

继承时将子类自身作为泛型参数传入:

public class GSIManagerExample : GSIManagerBase<GSIManagerExample> { /* ... */ }

运作方式

单例与驱动

GSIManagerBase<T> 内置线程安全的延迟单例(Double-Checked Locking)。首次调用任一静态方法时,自动创建 T 实例并执行其构造函数(基类构造函数会初始化阶段缓存),所有 Default API 皆通过该单例转调用对应的实例成员方法。

重要
  • GSIManagerBase<T> 为纯 C# 类(非 MonoBehaviour),不会自行更新,必须由主入口的 MonoBehaviour 调用 DriveStart(在 Start() 中)与 DriveUpdate(在 Update() 中)驱动运作。
  • 不可在子类构造函数中调用任何 Default API 静态方法,会导致 GetInstance() 递归而 StackOverflow(死循环);构造函数中请改用实例成员方法(如 AddGameStage)。

阶段注册与 ID

  • 每个阶段以唯一的 int id 注册至缓存。泛型重载未指定 id 时,以 typeof(U).GetHashCode() 作为 id(同类型仅能注册一个实例)。
  • 指定 id 的重载可自定义 id,同类型即可注册多个实例。
  • 相同 id 重复注册会输出警告日志并跳过,不会覆盖已有阶段。
  • 注册时管理器会自动调用 gameStage.SetId(id) 设置阶段识别码。

切换流程

模式生效时机行为
一般切换force = false下一次驱动更新仅记录目标 id,在下一次 DriveUpdate 检测到 id 变更时,依序执行「旧阶段 OnExit → 更新当前 id → 新阶段初始流程」。不允许切换至当前阶段(输出警告且不切换)。
强制切换force = true立即立即依序执行「旧阶段 OnExit → 更新当前 id → 新阶段初始流程」。不检查是否为同一阶段,可用于重新进入当前阶段。
注意
  • 新阶段的初始流程(OnCreate / OnEnter / 开启刷新)详见 GSIBase 生命周期与调用时序
  • 切换至未注册的 id 时,旧阶段仍会执行 OnExit,接着输出错误日志,且当前阶段会变为空。

继承实现示例

using OxGFrame.GSIFrame;
using UnityEngine;

// 自定义游戏阶段管理器:以子类自身作为泛型参数(CRTP)
public class GSIManagerExample : GSIManagerBase<GSIManagerExample>
{
public GSIManagerExample()
{
// 构造函数中注册各游戏阶段(仅能使用实例成员方法,不可调用 Default API)
this.AddGameStage<StartupStageExample>();
this.AddGameStage<LogoStageExample>();
this.AddGameStage<PatchStageExample>();
this.AddGameStage<LoginStageExample>();
this.AddGameStage<EnterStageExample>();
}

public override void OnStart()
{
// 启动第一个游戏阶段
this.ChangeGameStage<StartupStageExample>();
}

public override void OnUpdate(float dt = 0.0f)
{
base.OnUpdate(dt); // 必须调用 base,否则阶段不会切换与更新
}
}

// 主入口 MonoBehaviour,驱动管理器运作
public class Main : MonoBehaviour
{
private void Start()
{
GSIManagerExample.DriveStart();
}

private void Update()
{
GSIManagerExample.DriveUpdate(Time.deltaTime);
}
}

之后即可在任意处通过 Default API 操作阶段切换:

// 一般切换(下一次驱动更新时执行)
GSIManagerExample.ChangeStage<LoginStageExample>();

// 强制切换(立即执行)
GSIManagerExample.ChangeStage<LoginStageExample>(true);

提醒 可通过 Project 窗口右键模板快速创建管理器子类:Create → OxGFrame → GSI Frame → Template Scripts → Template GSIManager.cs (Game Stage Manager)

成员总览

静态方法(Default API)

继承后直接以子类类名调用(如 GSIManagerExample.ChangeStage<U>())。

方法说明
GetCurrentId获取当前阶段 id。
GetStage<U>获取已注册的阶段实例。
AddStage创建并注册游戏阶段。
DeleteStage从缓存移除已注册的阶段。
ChangeStage切换游戏阶段(一般/强制)。
DriveStart驱动启动(在主入口 Start() 中调用)。
DriveUpdate驱动更新(在主入口 Update() 中调用)。
Start / Update已弃用的旧版驱动接口。

可重写方法(virtual)

方法说明
OnStartDriveStart 调用,重写后在此启动第一个阶段。
OnUpdateDriveUpdate 每帧调用,默认执行阶段切换检测与刷新。

一般方法(实例成员)

供子类内部使用(如构造函数注册、OnStart 启动阶段)。

方法说明
GetCurrentGameStageId获取当前阶段 id(成员版本)。
GetGameStage<U>获取已注册的阶段实例(成员版本)。
AddGameStage注册游戏阶段(成员版本)。
DeleteGameStage移除已注册的阶段(成员版本)。
ChangeGameStage一般切换(成员版本)。
ChangeGameStageForce立即强制切换(成员版本)。

受保护成员(继承后可用)

成员类型说明
_dictGameStageDictionary<int, GSIBase>阶段缓存。
_incomingIdint待切换的目标阶段 id。
_currentIdint当前阶段 id(只读属性)。
_currentGameStageGSIBase当前阶段实例(只读属性)。
GetInstance()static T获取管理器单例(延迟创建、线程安全)。
UpdateGameStage(float dt = 0.0f)void检测阶段切换并刷新当前阶段(由 OnUpdate 调用)。
InitGameStage()void以当前 id 取出阶段并启动其初始流程。
ReleaseGameStage()void调用当前阶段的 OnExit

GetCurrentId

public static int GetCurrentId()

返回值

int — 当前阶段 id;尚未切换过任何阶段时为 0

说明

获取当前正在执行的阶段 id。


GetStage<U>

public static U GetStage<U>() where U : GSIBase
public static U GetStage<U>(int id) where U : GSIBase

参数

参数类型说明
idint阶段 id。未指定时,以 typeof(U).GetHashCode() 查找。

返回值

U — 对应的阶段实例;未找到时返回 null

说明

从缓存获取已注册的阶段实例。无参重载以类型 hash 查找,仅适用于未指定 id 注册的阶段;以自定义 id 注册者请使用 GetStage<U>(int id)

示例

var loginStage = GSIManagerExample.GetStage<LoginStageExample>();

AddStage

public static void AddStage<U>() where U : GSIBase, new()
public static void AddStage<U>(int id) where U : GSIBase, new()
public static void AddStage(int id, GSIBase gameStage)

参数

参数类型说明
idint阶段 id。未指定时,以 typeof(U).GetHashCode() 作为 id。
gameStageGSIBase已创建的阶段实例(以指定 id 注册)。

说明

创建(new U())并注册游戏阶段至管理器缓存,或以指定 id 直接注册已有实例。注册时自动调用 SetId(id) 设置阶段识别码。

注意 相同 id 重复注册会输出警告并跳过,不会覆盖已有阶段。

示例

// 以类型 hash 作为 id 注册
GSIManagerExample.AddStage<FightStageExample>();

// 以自定义 id 注册已有实例
GSIManagerExample.AddStage(0x01, new FightStageExample());

DeleteStage

public static void DeleteStage<U>() where U : GSIBase
public static void DeleteStage(int id)

参数

参数类型说明
idint阶段 id。未指定时,以 typeof(U).GetHashCode() 查找。

说明

从缓存移除已注册的阶段;未找到时不做任何操作。

注意 仅从缓存移除,不会触发该阶段的 OnExit


ChangeStage

public static void ChangeStage<U>(bool force = false) where U : GSIBase
public static void ChangeStage(int id, bool force = false)

参数

参数类型说明
idint目标阶段 id。泛型重载以 typeof(U).GetHashCode() 作为目标 id。
forcebool是否立即强制切换。
默认值false(一般切换)

说明

切换游戏阶段:

  • 一般切换force = false):记录目标 id,在下一次驱动更新时执行切换;不允许切换至当前阶段(输出警告且不切换)。
  • 强制切换force = true):立即依序执行「旧阶段 OnExit → 更新当前 id → 新阶段初始流程」;不检查是否为同一阶段,可用于重新进入当前阶段。

切换细节请参考切换流程GSIBase 生命周期与调用时序

示例

// 一般切换(下一次驱动更新时执行)
GSIManagerExample.ChangeStage<EnterStageExample>();

// 强制切换(立即执行,也可重新进入当前阶段)
GSIManagerExample.ChangeStage<EnterStageExample>(true);

DriveStart

public static void DriveStart()

说明

驱动启动,内部转调用单例的 OnStart。在主入口 MonoBehaviourStart() 中调用一次;首次调用会自动创建管理器单例(执行构造函数完成阶段注册)。

示例

private void Start()
{
GSIManagerExample.DriveStart();
}

DriveUpdate

public static void DriveUpdate(float dt = 0.0f)

参数

参数类型说明
dtfloat帧间隔时间(一般传入 Time.deltaTime)。
默认值0.0f

说明

驱动更新,内部转调用单例的 OnUpdate,执行阶段切换检测与当前阶段的 OnUpdate 刷新。在主入口 MonoBehaviourUpdate() 中每帧调用。

示例

private void Update()
{
GSIManagerExample.DriveUpdate(Time.deltaTime);
}

Start / Update(已弃用)

[Obsolete("Use DriveStart instead.")]
public static void Start()

[Obsolete("Use DriveUpdate instead.")]
public static void Update(float dt = 0.0f)

说明

旧版驱动接口,行为分别同 DriveStartDriveUpdate

注意 已标记 [Obsolete],请改用 DriveStart / DriveUpdate


OnStart

public virtual void OnStart()

说明

DriveStart 调用。基类为空实现,重写后通常在此调用 ChangeGameStage 启动第一个游戏阶段。


OnUpdate

public virtual void OnUpdate(float dt)

参数

参数类型说明
dtfloat帧间隔时间,由 DriveUpdate 传入。

说明

DriveUpdate 每帧调用。基类默认实现执行 UpdateGameStage(dt):检测阶段切换(一般切换在此时生效),并在当前阶段的 runUpdate 开启时调用其 OnUpdate

重要 重写时必须调用 base.OnUpdate(dt),否则阶段将不会切换与更新。


GetCurrentGameStageId

public int GetCurrentGameStageId()

返回值

int — 当前阶段 id;尚未切换过任何阶段时为 0

说明

GetCurrentId 的实例成员版本,供子类内部使用。


GetGameStage<U>

public U GetGameStage<U>() where U : GSIBase
public U GetGameStage<U>(int id) where U : GSIBase

参数

参数类型说明
idint阶段 id。未指定时,以 typeof(U).GetHashCode() 查找。

返回值

U — 对应的阶段实例;未找到时返回 null

说明

GetStage<U> 的实例成员版本,供子类内部使用。


AddGameStage

public void AddGameStage<U>() where U : GSIBase, new()
public void AddGameStage<U>(int id) where U : GSIBase, new()
public void AddGameStage(int id, GSIBase gameStage)

参数

参数类型说明
idint阶段 id。未指定时,以 typeof(U).GetHashCode() 作为 id。
gameStageGSIBase已创建的阶段实例(以指定 id 注册)。

说明

AddStage 的实例成员版本,在子类构造函数中注册各阶段时使用(构造函数中不可调用静态 Default API)。注册时自动调用 gameStage.SetId(id);相同 id 重复注册会输出警告并跳过;传入 null 实例会输出错误并跳过。

示例

public GSIManagerExample()
{
this.AddGameStage<StartupStageExample>();
}

DeleteGameStage

public void DeleteGameStage<U>() where U : GSIBase
public void DeleteGameStage(int id)

参数

参数类型说明
idint阶段 id。未指定时,以 typeof(U).GetHashCode() 查找。

说明

DeleteStage 的实例成员版本;未找到时不做任何操作。不允许删除当前运行中的阶段(会输出警告并跳过)。


ChangeGameStage

public void ChangeGameStage<U>() where U : GSIBase
public void ChangeGameStage(int id)

参数

参数类型说明
idint目标阶段 id。泛型重载以 typeof(U).GetHashCode() 作为目标 id。

说明

一般切换的实例成员版本:记录目标 id,在下一次驱动更新时执行切换;不允许切换至当前阶段;目标阶段不存在时,会输出错误并取消切换。通常在 OnStart 中调用以启动第一个阶段。


ChangeGameStageForce

public void ChangeGameStageForce<U>() where U : GSIBase
public void ChangeGameStageForce(int id)

参数

参数类型说明
idint目标阶段 id。泛型重载以 typeof(U).GetHashCode() 作为目标 id。

说明

强制切换的实例成员版本:立即依序执行「旧阶段 OnExit → 更新当前 id → 新阶段初始流程」;不检查是否为同一阶段,可用于重新进入当前阶段。