您好,欢迎来到Unity之家!   unity.jb51.net 
  • 首 页
  • 你问我答
  • 当前位置:首页 > 学习培训 > Unity编程 >
    在unity中 使用单例模式 Singleton
    时间:2015-04-20 09:36 来源:Unity之家 作者:unity.jb51.net 浏览:收藏 挑错 推荐 打印


    这几天想把在实习里碰到的一些好的技巧写在这里,也算是对实习的一个总结。

    今天要讲的是在Unity里应用一种非常有名的设计模式——单例模式


    开场白


    单例模式的简单介绍请看前面的链接,当然网上还有很多更详细的介绍,有兴趣的童靴可以了解一下。

    其实设计模式对于一个程序员来说还是非常有用的,这点随着学习的深入感受越来越深。


    好啦,现在说一下Unity里的单例模式。什么时候需要使用单例模式呢?正如它的名字一样,你认为一些

    东西在整个游戏中只有一个而你又想可以方便地随时访问它,这时你就可以考虑单例模式了。

    例如,你的游戏可能需要一个管理音乐播放的脚本,或者一个管理场景切换的脚本,或者一个管理玩家信息的通用脚本,

    又或者是管理游戏中各种常用UI的脚本。事实上,这些都是非常常用而且必要的。


    实现


    庆幸的是,单例模式的代码非常简单。下面是Singleton.cs的内容:


    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 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,判断该单例是否存在。



    (责任编辑:脚印)
    免责声明:Unity之家部分内容来源于互联网,如有侵权,请联系我们,本站将立即进行处理。