Unity Script 单例

本文深入探讨了单例模式的各种实现方式,包括非组件类、组件类、泛型单例及泛型组件单例等,并提供了具体的应用实例,如计分系统、时间跟踪和游戏结束广播等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Members of both singleton types are accessed the same way:

MySingleton.Instance.MySingletonMember;

The non-component example

public class MySingleton
{
	private static MySingleton instance;
 
	public MySingleton () 
	{
		if (instance != null)
		{
			Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
			return;
		}
 
		instance = this;
	}
 
	public static MySingleton Instance
	{
		get
		{
			if (instance == null)
			{
				new MySingleton ();
			}
 
			return instance;
		}
	}
}

Component-based example

using UnityEngine;
 
public class MySingleton : MonoBehaviour
{
	private static MySingleton instance;
 
	public static MySingleton Instance
	{
		get
		{
			if (instance == null)
			{
				instance = new GameObject ("MySingleton").AddComponent<MySingleton> ();
			}
 
			return instance;
		}
	}
 
	public void OnApplicationQuit ()
	{
		instance = null;
	}
}

Score tracking singleton

The singleton in this example keeps track of the game score. Getting and setting this value is done like so:

MySingleton.Instance.Score += 5;
Debug.Log ("Score is now: " + MySingleton.Instance.Score);

And the singleton class:

public class MySingleton
{
    private static MySingleton instance;
 
    public MySingleton () 
    {
        if (instance != null)
        {
            Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
            return;
        }
 
        instance = this;
    }
 
    public static MySingleton Instance
    {
        get
        {
            if (instance == null)
            {
                new MySingleton ();
            }
 
            return instance;
        }
    }
 
 
 
	private int score;
 
 
 
	public int Score
	{
		get
		{
			return score;
		}
		set
		{
			score = value;
		}
	}
}

Time tracking and GameOver broadcasting singleton

This singleton works similarly to the score tracking singleton by also maintaining a list of GameObjects which register and unregister themselves with the singleton in order to receive a "GameOver" message when the tracked timer reaches zero or lower. The timer is set just like the score is in the singleton above and GameObjects register and unregister with the singleton like so:

MySingleton.Instance.Register (gameObject);
MySingleton.Instance.Unregister (gameObject);

Registering and unregistering would likely make sense to do in Awake and OnDisable of a script attached to the GameObjects needing it.And the singleton class:

using System.Collections;
using UnityEngine;
 
 
 
public class MySingleton
{
    private static MySingleton instance;
 
    public MySingleton () 
    {
        if (instance != null)
        {
            Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
            return;
        }
 
        instance = this;
        Init ();
    }
 
    public static MySingleton Instance
    {
        get
        {
            if (instance == null)
            {
                new MySingleton ();
            }
 
            return instance;
        }
    }
 
 
 
	private int timer;
	private ArrayList listeners;
 
 
 
	private void Init ()
	{
		listeners = new ArrayList ();
	}
 
 
 
	public int Timer
	{
		get
		{
			return timer;
		}
		set
		{
			timer = value;
			if (timer <= 0)
			{
				foreach (GameObject listener in listeners)
				{
					listener.SendMessage ("GameOver");
				}
			}
		}
	}
 
 
 
	public GameObject RegisterListener (GameObject listener)
	{
		listeners.Add (listener);
 
		return listener;
	}
 
 
 
	public bool UnregisterListener (GameObject listener)
	{
		if (!listeners.Contains (listener))
		{
			return false;
		}
 
		listeners.Remove (listener);
	}
}

Mapping static methods to singleton methods

Having to go through the Instance property for every function of the singleton gets old fast. Really the user most of the time does not need to know that he is dealing with a singleton, so this:

MySingleton.Instance.Register (gameObject);
MySingleton.Instance.Unregister (gameObject);

should for simplicity be remapped to this:

MySingleton.Register (gameObject);
MySingleton.Unregister (gameObject);

To make the above true, simply make your methods static and have *them* take the pain of going through the Instance property - like so:

using System.Collections;
using UnityEngine;
 
 
 
public class MySingleton
{
    private static MySingleton instance;
 
    public MySingleton () 
    {
        if (instance != null)
        {
            Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
            return;
        }
 
        instance = this;
        Init ();
    }
 
    private static MySingleton Instance
    {
        get
        {
            if (instance == null)
            {
                new MySingleton ();
            }
 
            return instance;
        }
    }
 
 
 
	private int timer;
	private ArrayList listeners;
 
 
 
	private void Init ()
	{
		listeners = new ArrayList ();
	}
 
 
 
	public static int Timer
	{
		get
		{
			return Instance.timer;
		}
		set
		{
			Instance.timer = value;
			if (value <= 0)
			{
				foreach (GameObject listener in Instance.listeners)
				{
					listener.SendMessage ("GameOver");
				}
			}
		}
	}
 
 
 
	public static GameObject RegisterListener (GameObject listener)
	{
		Instance.listeners.Add (listener);
 
		return listener;
	}
 
 
 
	public static bool UnregisterListener (GameObject listener)
	{
		if (!Instance.listeners.Contains (listener))
		{
			return false;
		}
 
		Instance.listeners.Remove (listener);
	}
}

Voilá! Less cruft in the world! Everyone rejoice!

Generic Based Singleton

By Opless

This is uber simple, relies on the readonly keyword and generics to implement a threadsafe Singleton of practically any class.

Singleton<Foo>.Instance will be Foo (your own class) and guaranteed to be a singleton. The concept was lifted from a MSDN article that I recently discovered.

        public sealed class Singleton<T> where T : class, new()
        {
                /// <summary>
                /// Singleton implementation, readonly and static ensure thread safeness.
                /// </summary>
                public static readonly T Instance = new T ();
        }

Generic Based Singleton for MonoBehaviours

By Berenger

By inheriting from that class instead of MonoBehaviour, you can use all the singleton pattern without having to code it. It will search the object or intialiaze it in Awake, depending of the call order, or create if none exist. Just put your initilizations in Init() instead of Awake().

Example :

GameMaster.cs

public class GameMaster : MonoSingleton< GameMaster >
{
    public int difficulty = 0;
    public override void Init(){ difficulty = 5; }
}

OtherClass.cs

You forgot a "using UnityEngine;" fixed. :P

using UnityEngine;
public class OtherClass: MonoBehaviour
{
    void Start(){ print( GameMaster.instance.difficulty ); } // 5
}

The code :

using UnityEngine;
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
    private static T m_Instance = null;
    public static T instance
    {
        get
        {
            // Instance requiered for the first time, we look for it
            if( m_Instance == null )
            {
                m_Instance = GameObject.FindObjectOfType(typeof(T)) as T;
 
                // Object not found, we create a temporary one
                if( m_Instance == null )
                {
                    Debug.LogWarning("No instance of " + typeof(T).ToString() + ", a temporary one is created.");
                    m_Instance = new GameObject("Temp Instance of " + typeof(T).ToString(), typeof(T)).GetComponent<T>();
 
                    // Problem during the creation, this should not happen
                    if( m_Instance == null )
                    {
                        Debug.LogError("Problem during the creation of " + typeof(T).ToString());
                    }
                }
                m_Instance.Init();
            }
            return m_Instance;
        }
    }
    // If no other monobehaviour request the instance in an awake function
    // executing before this one, no need to search the object.
    private void Awake()
    {
        if( m_Instance == null )
        {
            m_Instance = this as T;
            m_Instance.Init();
        }
    }
 
    // This function is called when the instance is used the first time
    // Put all the initializations you need here, as you would do in Awake
    public virtual void Init(){}
 
    // Make sure the instance isn't referenced anymore when the user quit, just in case.
    private void OnApplicationQuit()
    {
        m_Instance = null;
    }
}
### 关于Unity脚本教程和文档 对于希望深入学习Unity脚本编程的人来说,官方提供的资源是非常宝贵的起点。两个PDF文件被认为是很好的入门材料:一个是`GUI Essentials.pdf`,另一个是`Scripting Tutorial.pdf`,这两个文件可以在安装目录下的Tutorial文件夹找到[^1]。 除了本地的PDF文档外,在线也有丰富的资源可以利用。如GitHub上的Unity SDK项目提供了更多关于特定功能如VRM的支持库,这有助于开发者了解如何通过C#脚本来实现更加复杂的功能[^2]。 为了更好地理解事件处理机制以及模式的应用场景,一篇讨论委托(Delegates)、事件(Events)的文章也值得阅读,这对于编写高效且结构良好的Unity脚本至关重要[^3]。 最后,《Unity基础核心技能与工作流程训练视频教程》不仅涵盖了基本概念介绍,还包括实际操作指南,帮助初学者快速上手并掌握必要的编程技巧来构建自己的游戏逻辑[^4]。 ```csharp // 示代码展示了一个简的Singleton模式实现方法 using UnityEngine; public class Singleton<T> : MonoBehaviour where T : MonoBehaviour { private static T _instance; public static T Instance { get { if (_instance == null){ _instance = FindObjectOfType<T>(); if(_instance == null){ GameObject singletonObject = new GameObject(); _instance = singletonObject.AddComponent<T>(); singletonObject.name = typeof(T).ToString() + " (Singleton)"; } } return _instance; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值