Unity3D中实例和单例的区别
Difference between instance and singleton in Unity3D
我有一个基本问题可以帮助新手更快地学习。如您所知,在 unity 中我们都使用单例和 class 的实例。我已经意识到一件事,我想确定我在想什么。你能帮我确定一下吗?
我在这样的情况下使用实例;
如果我有一个场景,我想使用实例作为一个图层来在脚本之间传输一些数据。我创建了一个空的游戏对象并将此代码分配为一个组件;
public class GameplayController : MonoBehaviour
{
public static GameplayController instance;
void Awake()
{
MakeInstance();
}
void MakeInstance()
{
if (instance == null)
{
instance = this;
}
else if(instance != null)
{
Destroy(gameObject);
}
}
}
我在某些情况下使用单例;
如果我有一个场景,我想使用单例模式作为一个层来在所有场景之间传输一些数据。我创建了一个空的游戏对象并将此代码分配为一个组件;
public class GameplayController : MonoBehaviour
{
public static GameplayController instance;
void Awake()
{
MakeSingleton();
void MakeSingleton()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else if(instance != null)
{
Destroy(gameObject);
}
}
}
所以,我想确定我是否走对了路?到现在一直有效,但是以后在大多数高级情况下会不会有问题?
你的代码是正确的,这是在Unity中创建单例的基本方法。
当您谈到实例与单例时,我得到了一些您可能不理解这个概念的感觉:单例的想法是对象只有一个(单个)实例。
所以你有一个静态的属性; class 上的 static 修饰符使其无法使用 new
关键字实例化。当您将它添加到 属性(就像您所做的那样)时,这意味着您可以从任何地方访问它,而无需实例化包含的 class。
GameplayController.instance
在您的 MakeInstance() 中验证该实例尚未分配给某个实例,然后将其设置为该实例。
要进一步遵循单例模式,您可能需要确保在加载新场景时您的对象不会被破坏:
if (instance == null)
{
DontDestroyOnLoad(gameObject);
instance = this;
}
以后应该不会出问题的;然而,单例模式是一种糟糕的模式,但它在原型设计中有其用处;这很简单。
您可能遇到的问题是您的代码将依赖于您的单例 classes,如果您忘记将 class 添加到场景中,或者如果您有实例化这些 classes 的早期场景你必须在调试时首先启动该场景等
我个人使用 Singleton class 来扩展以确保所有 Singleton 具有相同的功能并减少每个 Singleton 中的膨胀 class 等:
using UnityEngine;
public abstract 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)
{
var instances = FindObjectsOfType<T>();
if (instances.Length > 1)
{
Debug.LogError("[Singleton] Something went really wrong " +
", there are too many Singletons; deleting them: ");
for (int i = 1; i < instances.Length; i++)
{
Debug.LogError("Deleting " + instances[i].gameObject.name);
Destroy(instances[i].gameObject);
}
_instance = FindObjectOfType<T>();
return _instance;
}
if (instances.Length > 0)
_instance = instances[0];
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.");
}
}
return _instance;
}
}
}
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
/// <summary>
/// When Unity quits, it destroys objects in a random order.
/// In principle, a Singleton is only destroyed when application quits.
/// If any script calls Instance after it have been destroyed,
/// it will create a buggy ghost object that will stay on the Editor scene
/// even after stopping playing the Application. Really bad!
/// So, this was made to be sure we're not creating that buggy ghost object.
/// </summary>
private static bool applicationIsQuitting = false;
public void OnDestroy()
{
applicationIsQuitting = true;
}
}
然后像这样使用:
public class MySingleton : Singleton<MySingleton>
{
// Don't use the Awake method, Singleton uses it to initialize
void Start() {
Debug.Log("I'm a Singleton, access me through MySingleton.Instance");
}
}
我有一个基本问题可以帮助新手更快地学习。如您所知,在 unity 中我们都使用单例和 class 的实例。我已经意识到一件事,我想确定我在想什么。你能帮我确定一下吗?
我在这样的情况下使用实例;
如果我有一个场景,我想使用实例作为一个图层来在脚本之间传输一些数据。我创建了一个空的游戏对象并将此代码分配为一个组件;
public class GameplayController : MonoBehaviour
{
public static GameplayController instance;
void Awake()
{
MakeInstance();
}
void MakeInstance()
{
if (instance == null)
{
instance = this;
}
else if(instance != null)
{
Destroy(gameObject);
}
}
}
我在某些情况下使用单例;
如果我有一个场景,我想使用单例模式作为一个层来在所有场景之间传输一些数据。我创建了一个空的游戏对象并将此代码分配为一个组件;
public class GameplayController : MonoBehaviour
{
public static GameplayController instance;
void Awake()
{
MakeSingleton();
void MakeSingleton()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else if(instance != null)
{
Destroy(gameObject);
}
}
}
所以,我想确定我是否走对了路?到现在一直有效,但是以后在大多数高级情况下会不会有问题?
你的代码是正确的,这是在Unity中创建单例的基本方法。
当您谈到实例与单例时,我得到了一些您可能不理解这个概念的感觉:单例的想法是对象只有一个(单个)实例。
所以你有一个静态的属性; class 上的 static 修饰符使其无法使用 new
关键字实例化。当您将它添加到 属性(就像您所做的那样)时,这意味着您可以从任何地方访问它,而无需实例化包含的 class。
GameplayController.instance
在您的 MakeInstance() 中验证该实例尚未分配给某个实例,然后将其设置为该实例。
要进一步遵循单例模式,您可能需要确保在加载新场景时您的对象不会被破坏:
if (instance == null)
{
DontDestroyOnLoad(gameObject);
instance = this;
}
以后应该不会出问题的;然而,单例模式是一种糟糕的模式,但它在原型设计中有其用处;这很简单。
您可能遇到的问题是您的代码将依赖于您的单例 classes,如果您忘记将 class 添加到场景中,或者如果您有实例化这些 classes 的早期场景你必须在调试时首先启动该场景等
我个人使用 Singleton class 来扩展以确保所有 Singleton 具有相同的功能并减少每个 Singleton 中的膨胀 class 等:
using UnityEngine;
public abstract 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)
{
var instances = FindObjectsOfType<T>();
if (instances.Length > 1)
{
Debug.LogError("[Singleton] Something went really wrong " +
", there are too many Singletons; deleting them: ");
for (int i = 1; i < instances.Length; i++)
{
Debug.LogError("Deleting " + instances[i].gameObject.name);
Destroy(instances[i].gameObject);
}
_instance = FindObjectOfType<T>();
return _instance;
}
if (instances.Length > 0)
_instance = instances[0];
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.");
}
}
return _instance;
}
}
}
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
/// <summary>
/// When Unity quits, it destroys objects in a random order.
/// In principle, a Singleton is only destroyed when application quits.
/// If any script calls Instance after it have been destroyed,
/// it will create a buggy ghost object that will stay on the Editor scene
/// even after stopping playing the Application. Really bad!
/// So, this was made to be sure we're not creating that buggy ghost object.
/// </summary>
private static bool applicationIsQuitting = false;
public void OnDestroy()
{
applicationIsQuitting = true;
}
}
然后像这样使用:
public class MySingleton : Singleton<MySingleton>
{
// Don't use the Awake method, Singleton uses it to initialize
void Start() {
Debug.Log("I'm a Singleton, access me through MySingleton.Instance");
}
}