Unity的MonoBehaviour单例设置
Unity的MonoBehaviour單例設置
- MonoBehaviour的基本單例模式
- MonoBehaviour單例的泛型基類
- MonoBehaviour單例腳本的問題
- 解決方案
- 互斥鎖Mutex
- 使用Editor.OnEnable()監測
- 想法
- 實現
- 參考鏈接
MonoBehaviour的基本單例模式
根據Unity的MonoBehaviour腳本創建單例模式,我們一般的創建方式是:
using UnityEngine;public class MonoSingleton : MonoBehaviour {public static MonoSingleton Instance = null;protected virtual void Awake(){Instance = this;} }MonoBehaviour單例的泛型基類
使用泛型之后是:
using UnityEngine;public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T> {public static T Instance = null;protected virtual void Awake(){Instance = this as T;} }MonoBehaviour單例腳本的問題
但這樣是有問題的單例模式,在其他的文章中提到單例模式的原則(目的)是“保證一個類只有一個實例,并提供全局訪問點”。
根據上面所述,對比我們這里創建的MonoBehaviour類的單例并沒有對MonoBehaviour類的構造函數進行非公有化,我們依然可以自由的創建該類的實例對象。因為MonoBehaviour類有可視化操作的特點(手動拖拽到場景GameObject上),這部分是Unity內部封裝的,為了不出現不必要的錯誤,我們不能從根本上(即Unity的內部)改變這點。
解決方案
互斥鎖Mutex
經過查找資料,找到不少方法,但似乎效果都不是很理想,或者說不是我想要的效果。但這里我還是分享一個看起來不錯的方式:就是使用互斥類Mutex(互斥鎖),代碼如下,
/// <summary> /// Unity的Mono單例基類 /// </summary> /// <typeparam name="T">對應的子類</typeparam> public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T> {private static T m_Instance = null;private new static string name;private static Mutex mutex;//互斥類Mutexpublic static T Instance{get{if (m_Instance == null){if (IsSingle()){m_Instance = new GameObject(name, typeof(T)).GetComponent<T>();m_Instance.Init();}}return m_Instance;}}private static bool IsSingle(){name = "Singleton of " + typeof(T).ToString();mutex = new Mutex(false, name, out bool createdNew);mutex.WaitOne();return createdNew;}private bool m_isDestroy = true;protected virtual void Awake(){m_isDestroy = true;if (m_Instance == null){if (IsSingle()){m_Instance = this as T;m_Instance.Init();}}else{Debug.LogError("[Singleton] " + typeof(T).Name + " should never be more than 1 in scene!Owner is “" + transform.name + "”.");m_isDestroy = false;Destroy(this);}}protected abstract void Init();protected abstract void DisInit();private void OnDestroy(){if (m_Instance != null){if (m_isDestroy){if (null != mutex){mutex.ReleaseMutex();}m_Instance = null;}DisInit();}}private void OnApplicationQuit(){if (null != mutex){mutex.ReleaseMutex();mutex.Close();mutex = null;}} }根據互斥鎖Mutex的特點,使將本在程序運行之初,只承認第一個創建的MonoBehaviour單例類,并將多余的的Destroy銷毀掉,只留下一個。
這不失為一種好辦法。
使用Editor.OnEnable()監測
想法
但我想的是MonoBehaviour單例類腳本,在編輯器狀態下,被手動拖拽到GameObject上之時,便能識別,場景中是否已經存在該單例類;如果已存在則不會再將該腳本創建(拖拽)到任何GameObject上。
而這種操作就只能在UnityEditor庫下,每個MonoBehaviour腳本對應的Editor中才能實現。
實現
我經過多次嘗試,終于實現了以上描述的效果,即在Editor的OnEnable()函數中實現,代碼如下:
using UnityEditor; using UnityEngine;[CustomEditor(typeof(*****), true), CanEditMultipleObjects] public class MonoSingletonEditor : Editor {private static ***** tInstance = null;protected ***** sMono;protected virtual void OnEnable(){sMono = ((*****)target);if (null == tInstance){tInstance = sMono;}else if (sMono != tInstance){DestroyImmediate(target);Debug.LogError("There can only be one in this script scenario!");return;}} }代碼中的 “ ***** ” 是對應的MonoBehaviour單例腳本名,而且這也用到了Unity內部封裝的一些函數,故這種方式是無法泛型的。每一個MonoBehaviour單例就要有一個相對的該類。
但經過我測試,也確實是實現了我上面描述的效果,再結合互斥鎖Mutex的泛型基類,就可以很好的防止該類被多次創建。
參考鏈接
https://www.cnblogs.com/fastcam/p/5924036.html
總結
以上是生活随笔為你收集整理的Unity的MonoBehaviour单例设置的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一阶线性常微分方程解法总结 Summar
- 下一篇: autojspro常用的代码和公共函数搜