欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

Unity的MonoBehaviour单例设置

发布时间:2023/12/29 34 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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单例设置的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。