Unity里的单例对象创建方法

/ 6

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的单例类的生命周期方法都最好在封装类中实现,并提供对应的虚方法给子类重写。