跳至主要内容

MonoSingleton

重要 注意 提醒

Coding Style wiki


MonoSingleton<T>SingletonSystemMonoBehaviour 單例基類 (線程鎖保護),取得實例時會優先查找場景上的既有實例,否則自動建立 GameObject 掛載組件,支持 DontDestroyOnLoad 跨場景常駐控制,並以 OnCreate / OnStart / OnRelease 生命週期掛勾取代 Unity 的 Awake / Start / OnDestroy

命名空間OxGKit.SingletonSystem
類型public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
原始碼MonoSingleton.cs
using OxGKit.SingletonSystem;

提醒 不需要掛載於 GameObject 的純資料或邏輯管理類,請改用 NewSingleton

快速上手

using OxGKit.SingletonSystem;

public class GameManager : MonoSingleton<GameManager>
{
protected override void OnCreate() { /* Call by Unity.Awake */ }

protected override void OnStart() { /* Call by Unity.Start */ }

protected override void OnRelease() { /* Call by Unity.OnDestroy */ }

public void SaveGame() { /* ... */ }
}

// 取得實例並訪問 (場景查找或自動建立,預設 DontDestroyOnLoad)
GameManager.GetInstance().SaveGame();

// 場景限定單例 (隨場景卸載銷毀)
GameManager.GetInstance(dontDestroyOnLoad: false);

// 開機明確初始實例 (warm-up)
GameManager.InitInstance();

// 銷毀實例 (連同 GameObject)
GameManager.DestroyInstance();

通用規則

生命週期對應

基類已將 Awake()Start()OnDestroy() 實作為私有方法,並以旗標防護對應觸發以下掛勾:

Unity 方法掛勾旗標
AwakeOnCreateisCreated
StartOnStartisStarted
OnDestroyOnReleaseisReleased (並重置 isCreatedisStarted 與實例引用)

重要 不可實作 Awake()Start()OnDestroy() (基類已佔用),其餘 Unity 方法 (UpdateOnEnable 等) 皆可正常實作。

實例建立規則

  1. 場景預先放置:實例於 Awake 自動註冊為單例,並依 Inspector 上的 dontDestroyOnLoad 欄位決定是否常駐 (詳見模塊介紹)。
  2. 程式動態建立:呼叫 GetInstance 時若無實例,會查找場景既有實例 (FindObjectsOfType 取第一個),否則以 new GameObject(typeof(T).Name) 自動建立並掛載組件。

注意 GetInstance 僅於 Play Mode 進行實例建立 (Application.isPlaying)。

注意 同一類型於場景上放置多個實例時不會自動去重 (查找取第一個),請避免於多場景 (Additive) 重複放置。

提醒OnCreate / OnStart 註冊的事件,請於 OnRelease 解除註冊,避免常駐單例累積失效委派;於關閉/銷毀流程中訪問單例,建議先以 CheckInstanceExists 檢查,避免於退出階段又重新建立實例。


成員

成員說明
public bool dontDestroyOnLoad(實例欄位) 是否於 Awake 進行 DontDestroyOnLoad 常駐標記,預設 true,場景預先放置時可於 Inspector 配置。
public static bool isCreatedOnCreate 是否已觸發。
public static bool isStartedOnStart 是否已觸發。
public static bool isReleased實例是否已銷毀 (OnRelease 已觸發),新實例 Awake 時會重置為 false

實例管理

方法總覽

方法說明
GetInstance取得單例實例 (場景查找或自動建立)。
InitInstance初始單例實例 (等同呼叫 GetInstance)。
CheckInstanceExists檢查實例是否存在。
DestroyInstance銷毀單例實例。

GetInstance

public static T GetInstance(bool dontDestroyOnLoad = true)

取得單例實例 (線程鎖保護)。若實例尚不存在 (僅於 Play Mode),會優先查找場景上的既有實例,否則自動建立 new GameObject(typeof(T).Name) 並掛載組件;dontDestroyOnLoad 參數為 true 時會標記實例並執行 DontDestroyOnLoad

// 需要跨場景常駐 (預設)
GameManager.GetInstance();

// 不需要跨場景常駐 (首次取得時設定一次即可)
StageManager.GetInstance(dontDestroyOnLoad: false);

注意 dontDestroyOnLoad 參數於首次建立實例時生效,請於第一次取得實例的呼叫點決定並保持一致。

InitInstance

public static void InitInstance(bool dontDestroyOnLoad = true)

初始單例實例 (等同呼叫 GetInstance),適合於開機流程明確控制建立順序 (warm-up),避免延遲建立造成的順序問題。

private void Awake()
{
GameManager.InitInstance();
AudioManager.InitInstance();
}

CheckInstanceExists

public static bool CheckInstanceExists()

檢查實例是否存在 (不會觸發建立)。

if (GameManager.CheckInstanceExists())
GameManager.GetInstance().SaveGame();

DestroyInstance

public static void DestroyInstance(bool gameObjectIncluded = true)

銷毀單例實例;gameObjectIncludedtrue連同 GameObject 一併銷毀,為 false 時僅銷毀組件本身。銷毀後會觸發 OnRelease 並重置狀態旗標與實例引用,之後可再重新建立新實例。

// 連同 GameObject 一併銷毀 (預設)
GameManager.DestroyInstance();

// 僅銷毀組件本身 (保留 GameObject)
GameManager.DestroyInstance(gameObjectIncluded: false);

生命週期掛勾

方法總覽

方法說明
OnCreate由 Unity Awake 觸發。
OnStart由 Unity Start 觸發。
OnRelease由 Unity OnDestroy 觸發。

OnCreate

protected abstract void OnCreate()

由 Unity Awake 觸發 (以 isCreated 旗標防護僅觸發一次),於此實作初始邏輯。

OnStart

protected abstract void OnStart()

由 Unity Start 觸發 (以 isStarted 旗標防護僅觸發一次),於此實作啟動邏輯。

OnRelease

protected abstract void OnRelease()

由 Unity OnDestroy 觸發,於此實作釋放邏輯 (解除事件註冊、釋放資源);觸發後 isReleasedtrue,並重置 isCreatedisStarted 與實例引用。