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常用的代码和公共函数搜