unity 单列
1.
public class SingletonUI<T> : MonoBehaviour where T : SingletonUI<T> { private static T instance; public static T getInstance() { if (!instance) { instance = (T)GameObject.FindObjectOfType(typeof(T)); if (!instance) { Logger.error(Module.Framework, "There needs to be one active " + typeof(T) + " script on a GameObject in your scene."); } } return instance; } }
调用方法:
public class FavoriteMovie : SingletonUI<FavoriteMovie> { // Use this for initialization void Start () { //Init(); } // Update is called once per frame void Update () { } public void doubanFunction() { Debug.Log("豆瓣"); Application.OpenURL(doubanUrl); } } } //然后在其他的类里面调用: FavoriteMovie.getInstance().doubanFunction();
上面的模式的缺点:就是每个单列脚本必须先挂在一个GameObject上面。
接下来就是转发别人写的单列模式了:
http://bbs.9ria.com/thread-66692-1-1.html
在Unity3D中可以用不同的方法来实现单例,第一种是通常用法,第二种是自我包含法,第三种方法粗制滥造法,第四种是为C#开发者准备的,计数器法。
1.通常用法
通常用法是在相关类加入GetInstance()的静态方法,检查实例是否存在。如果存在,则返回。如果不存在,则返回一个“需要用游戏元素类关联”的调试警告错误.
public class MyClass { private static MyClass instance; public static MyClass GetInstance() { if (!instance) { instance = GameObject.FindObjectOfType(typeof(MyClass)); if (!instance) Debug.LogError("There needs to be one active MyClass script on a GameObject in your scene."); } return instance; } }
2.自我包含法
有一次玩Trench Run game,我意识到我的场景类里存在许多的GameObject。所以,我开发了自我包含的单例。如果没找找到实例,就会创建它自己的GameObject,注重通过AddComponent()方法返回来关联实例类,而不需要在IDE中创建一个GameObject在设计时弄乱你的场景。
public class Logger : MonoBehaviour { private static Logger instance; private static GameObject container; public static Logger GetInstance() { if( !instance ) { container = new GameObject(); container.name = "Logger"; instance = container.AddComponent(typeof(Logger)) as Logger; } return instance; } }
3.粗制滥造法
粗制滥造法很简单,为实例设置一个公共静态属性,初始化Awake()方法,设计时关联一个GameObject. 可以用以下方法访问:
MyClass.instance.DoSomething();
public class MyClass
{
public static MyClass instance;
public void Awake()
{
MyClass.instance = this;
}
}
在ActionScript里访问外在类的其他方法比访问一个属性要慢很多,我不知道这是否属实(我怀疑),但是在过去几年里我在Flash上噩梦般的优化,我通常用的是这种方法。也许有些习惯永远也改不了的!(或者我本来就偏执于此)
祝你愉快!
4.计数器法
以上的第一种方法和第二种方法得利于使用访问器而不是一个方法。关于本提示要感谢Cliff Owen.
public class MyClass { private static MyClass _instance; public static MyClass Instance { get { if (!_instance) { _instance = GameObject.FindObjectOfType(typeof(MyClass)); if (!_instance) { GameObject container = new GameObject(); container.name = "MyClassContainer"; _instance = container.AddComponent(typeof(MyClass)) as MyClass; } } return _instance; } } }
然后你就可以用以下方士简单而粗制滥造的访问它:
MyClass.Instance.DoSomething();
点评:方法1通常用法 一般我们的模板用这个,偶尔我也会用3.粗制滥造法。方法二:其实参考一下NGUI的SpringPosition 类
http://blog.csdn.net/candycat1992/article/details/10960731
现在说一下Unity里的单例模式。什么时候需要使用单例模式呢?正如它的名字一样,你认为一些东西在整个游戏中只有一个而你又想可以方便地随时访问它,这时你就可以考虑单例模式了。例如,你的游戏可能需要一个管理音乐播放的脚本,或者一个管理场景切换的脚本,或者一个管理玩家信息的通用脚本,又或者是管理游戏中各种常用UI的脚本。事实上,这些都是非常常用而且必要的。
using System; using System.Collections; using System.Collections.Generic; public class Singleton : MonoBehaviour { private static GameObject m_Container = null; private static string m_Name = "Singleton"; private static Dictionary<string, object> m_SingletonMap = new Dictionary<string, object>(); private static bool m_IsDestroying = false; public static bool IsDestroying { get { return m_IsDestroying; } } public static bool IsCreatedInstance(string Name) { if(m_Container == null) { return false; } if (m_SingletonMap!=null && m_SingletonMap.ContainsKey(Name)) { return true; } return false; } public static object getInstance (string Name) { if(m_Container == null) { Debug.Log("Create Singleton."); m_Container = new GameObject (); m_Container.name = m_Name; m_Container.AddComponent (typeof(Singleton)); } if (!m_SingletonMap.ContainsKey(Name)) { if(System.Type.GetType(Name) != null) { m_SingletonMap.Add(Name, m_Container.AddComponent (System.Type.GetType(Name))); } else { Debug.LogWarning("Singleton Type ERROR! (" + Name + ")"); } } return m_SingletonMap[Name]; } public static void RemoveInstance(string Name) { if (m_Container != null && m_SingletonMap.ContainsKey(Name)) { UnityEngine.Object.Destroy((UnityEngine.Object)(m_SingletonMap[Name])); m_SingletonMap.Remove(Name); Debug.LogWarning("Singleton REMOVE! (" + Name + ")"); } } void Awake () { Debug.Log("Awake Singleton."); DontDestroyOnLoad (gameObject); } void Start() { Debug.Log("Start Singleton."); } void Update() { } void OnApplicationQuit() { Debug.Log("Destroy Singleton"); if(m_Container != null) { GameObject.Destroy(m_Container); m_Container = null; m_IsDestroying = true; } } }
- 当我们在其他代码里需要访问某个单例时,只需调用getInstance函数即可,参数是需要访问的脚本的名字。我们来看一下这个函数。它首先判断所有单例所在的容器m_Container是否为空(实际上就是场景中是否存在一个Gameobject,上面捆绑了一个Singleton脚本),如果为空,它将自动创建一个对象,然后以“Singleton”命名,再捆绑Singleton脚本。m_SingletonMap是负责维护所有单例的映射。当第一次访问某个单例时,它会自动向m_Container上添加一个该单例类型的Component,并保存在单例映射中,再返回这个单例。因此,我们可以看出,单例的创建完全都是自动的,你完全不需要考虑在哪里、在什么时候捆绑脚本,这是多么令人高兴得事情!
- 在Awake函数中,有一句代码DontDestroyOnLoad (gameObject);,这是非常重要的,这句话意味着,当我们的场景发生变化时,单例模式将不受任何影响。除此之外,我们还要注意到,这句话也必须放到Awake函数,而不能放到Start函数中,这是由两个函数的执行顺序决定的,如果反过来,便可能会造成访问单例不成功,下面的例子里会更详细的介绍;
- 在OnApplicationQuit函数中,我们将销毁单例模式。
- 最后一点很重要:一定不要在OnDestroy函数中直接访问单例模式!这样很有可能会造成单例无法销毁。这是因为,当程序退出准备销毁单例模式时,我们在其他脚本的OnDestroy函数中再次请求访问它,这样将重新构造一个新的单例而不会被销毁(因为之前已经销毁过一次了)。如果一定要访问的话,一定要先调用IsCreatedInstance,判断该单例是否存在。
例子
using UnityEngine; using System.Collections; public class SingletonSample : MonoBehaviour { // Use this for initialization void Start () { TestSingleton(); } // Update is called once per frame void Update () { } private void TestSingleton() { LitJsonSample litjson = Singleton.getInstance("LitJsonSample") as LitJsonSample; litjson.DisplayFamilyList(); } // void OnDestroy() { // LitJsonSample litjson = Singleton.getInstance("LitJsonSample") as LitJsonSample; // // litjson.DisplayFamilyList(); // } }