Unity里的单例对象不同场景有不同的写法,下面是最常见的几种。
普通类
不是继承MonoBehaviour
类的普通类,不能被挂载到Unity游戏物体上。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test { private static Test _Instance; public static Test Instance { get { if (_Instance == null) { _Instance = new Test(); } return _Instance; } } }
多游戏物体
我们都知道,继承自MonoBehaviour
并挂载到游戏物体上的脚本,是由Unity去创建对象的,挂载了多少次就会创建多少个这个脚本的实例对象。
根据脚本的生命周期,如果一个脚本被挂载到多个游戏物体上,Awake()
方法会被执行多次,我们要写单例就不能在这个方法中直接赋值了。我们可以自己创建一个空游戏物体来实现,不过这种方式并不完全是脚本的单例对象,只是保证_Instance
在内存中只存在一份而已。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { private static Test _Instance; public static Test Instance { get { if (_Instance == null) { // 在场景中创建一个名字为Test的空游戏物体 GameObject obj = new GameObject("Test"); // 给这个空游戏物体添加一个Test组件 _Instance = obj.AddComponent<Test>(); // 加载新场景时不会销毁这个空物体 DontDestroyOnLoad(obj); } return _Instance; } } }
单游戏物体
如果确定一个脚本只会被挂载到一个游戏物体上,可以直接在Awake()
方法中赋值:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { private static Test _Instance; public static Test Instance { get { return _Instance; } } void Awake() { _Instance = this; } }
封装类
我们将单例封装好,在使用的时候直接在需要使用单例的类里继承我们的封装类即可。
普通单例类:
using System; /// <summary> /// 普通单例类 /// </summary> /// <typeparam name="T">子类类型</typeparam> public class Singleton<T> : IDisposable where T : new() { private static T _Instance; public static T Instance { get { if (_Instance == null) { _Instance = new T(); } return _Instance; } } public virtual void Dispose() { } }
需要继承MonoBehaviour
的单例类:
using UnityEngine; /// <summary> /// 继承自MonoBehaviour的单例类 /// </summary> /// <typeparam name="T">子类类型</typeparam> public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour { private static T _Instance; public static T Instance { get { if (_Instance == null) { GameObject obj = new GameObject(typeof(T).Name); _Instance = obj.GetOrAddComponent<T>(); DontDestroyOnLoad(obj); } return _Instance; } } void Awake() { OnAwake(); } void Start() { OnStart(); } void Update() { OnUpdate(); } void OnDestroy() { BeforeOnDestroy(); } protected virtual void OnAwake() { } protected virtual void OnStart() { } protected virtual void OnUpdate() { } protected virtual void BeforeOnDestroy() { } }
需要继承自MonoBehaviour
的单例类的生命周期方法都最好在封装类中实现,并提供对应的虚方法给子类重写。