我是 Unity 的初学者。
我在学习时遇到一个问题。
我参考了下面的文档。
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
private static object _lock = new object();
public static T Instance
{
get
{
if (applicationIsQuitting) {
Debug.LogWarning("[Singleton] Instance '"+ typeof(T) +
"' already destroyed on application quit." +
" Won't create again - returning null.");
return null;
}
lock(_lock)
{
if (_instance == null)
{
_instance = (T) FindObjectOfType(typeof(T));
if ( FindObjectsOfType(typeof(T)).Length > 1 )
{
Debug.LogError("[Singleton] Something went really wrong " +
" - there should never be more than 1 singleton!" +
" Reopening the scene might fix it.");
return _instance;
}
if (_instance == null)
{
GameObject singleton = new GameObject();
_instance = singleton.AddComponent<T>();
singleton.name = "(singleton) "+ typeof(T).ToString();
DontDestroyOnLoad(singleton);
Debug.Log("[Singleton] An instance of " + typeof(T) +
" is needed in the scene, so '" + singleton +
"' was created with DontDestroyOnLoad.");
} else {
Debug.Log("[Singleton] Using instance already created: " +
_instance.gameObject.name);
}
}
return _instance;
}
}
}
private static bool applicationIsQuitting = false;
public void OnDestroy () {
applicationIsQuitting = true;
}
}
如果实例为空,为什么要将 GameObject 添加到 AddComponent ?
为什么使用 FindObject 函数?
以及为什么在 Unity 中使用 Singleton?
我不知道Singleton总体流程..
请给我代码审查..
作为初学者,我了解的不多。我需要你的帮助。
请给我你的想法。
如果实例为空,为什么要将 GameObject 添加到 AddComponent ?
如果您要创建的脚本实例为空
if (_instance == null)
:
1.创建新的游戏对象
GameObject singleton = new GameObject();
2。创建该脚本的新实例并将其附加到上面创建的游戏对象。在 Unity 中,组件必须附加到 GameObject。
AddComponent
函数用于将组件附加到游戏对象。
_instance = singleton.AddComponent<T>();
为什么要使用 FindObject 函数?
如果您要创建的脚本实例为空
if (_instance == null)
,请检查该脚本实例是否已存在于场景中。 FindObjectOfType
函数仅用于查找此类脚本。假设我们有一个名为 SceneLoader
的脚本,并且将 SceneLoader
传递给 Singleton
类,它将检查 SceneLoader
的实例是否已存在于场景中并返回该实例。如果不存在则返回null
。
为什么在Unity中使用Singleton?
当您只想在场景中拥有一个某种脚本类型的实例时,可以使用它。另外,使用
DontDestroyOnLoad
意味着即使加载下一个场景,该实例仍然存在。它不会像其他脚本一样被破坏。
请给我代码审查
您可以在 codereview 网站上请求代码改进。如果您是 Unity 新手,您可以在他们的网站上找到 Unity 项目教程,让您轻松入门这里。
我认为我有一个优雅的解决方案来解决这个问题(通用单例):
public static class Singleton
{
/************************************************************/
#region Functions
public static T Get<T>(
bool findObjectOfType = false,
bool dontDestroyOnLoad = false,
bool unparentGameObject = false) where T : MonoBehaviour
{
if (findObjectOfType && SingletonInstance<T>.instance == null)
{
TrySet(Object.FindObjectOfType<T>(), dontDestroyOnLoad);
LogManager.Log($"called Get<{typeof(T)}>() before instance was set; calling FindObjectOfType<{typeof(T)}>");
}
return SingletonInstance<T>.instance;
}
public static bool TrySet<T>(
T instance,
bool dontDestroyOnLoad = false,
bool unparentGameObject = false) where T : MonoBehaviour
{
// NOTE: method does not need to be called; BUT if called, FindObjectOfType() is avoided during lazy init
if (SingletonInstance<T>.instance != null)
{
LogManager.Log($"{instance.name} called Set<{typeof(T)}>() when singleton already exists");
if (!IsSingleton(instance))
{
LogManager.Log($"there are two different singleton instances, calling DestroyImmediate for {instance.name}");
Object.DestroyImmediate(instance.gameObject);
}
return false;
}
else if (instance != null)
{
SingletonInstance<T>.instance = instance;
if (unparentGameObject) instance.transform.SetParent(null);
if (dontDestroyOnLoad) Object.DontDestroyOnLoad(instance.gameObject);
return true;
}
else
{
LogManager.LogError($"called Set<{typeof(T)}>() when given instance is null");
return false;
}
}
public static bool IsSingleton<T>(T instance) where T : MonoBehaviour
{
return ReferenceEquals(SingletonInstance<T>.instance, instance);
}
#endregion
/************************************************************/
#region Subclasses
private static class SingletonInstance<T> where T : MonoBehaviour
{
public static T instance;
}
#endregion
/************************************************************/
}
其中具有/是
singleton的
class
看起来像:
/************************************************************/
#region Properties
public static TestRunner Instance => Singleton.Get<TestRunner>(findObjectOfType: true);
#endregion
/************************************************************/
#region Functions
private void Awake() => Singleton.TrySet(this, dontDestroyOnLoad);
#endregion
/************************************************************/
你可以创建一个 MonoSingleton 类,如下所示:
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
/************************************************************/
#region Fields
[Header("Singleton Settings")]
[Tooltip("whether Object.DontDestroyOnLoad() is called on this")]
[SerializeField] private bool dontDestroyOnLoad;
[Tooltip("whether this GameObject unparents itself")]
[SerializeField] private bool unparentGameObject;
#endregion
/************************************************************/
#region Properties
private T _Instance => this as T;
public static T Instance => Singleton.Get<T>();
#endregion
/************************************************************/
#region Functions
protected void Awake()
{
if (Singleton.TrySet(_Instance, dontDestroyOnLoad, unparentGameObject))
{
MonoSingleton_Awake();
}
}
protected void OnDestroy()
{
if (Singleton.IsSingleton(_Instance))
{
MonoSingleton_OnDestroy();
}
}
protected void OnEnable()
{
if (Singleton.IsSingleton(_Instance))
{
MonoSingleton_OnEnable();
}
}
protected void OnDisable()
{
if (Singleton.IsSingleton(_Instance))
{
MonoSingleton_OnDisable();
}
}
protected virtual void MonoSingleton_Awake() {}
protected virtual void MonoSingleton_OnEnable() {}
protected virtual void MonoSingleton_OnDisable() {}
protected virtual void MonoSingleton_OnDestroy() {}
#endregion
/************************************************************/
}