• Unity中实现全局管理类的几种方式


    (搬运自我在SegmentFault的博客)

    如何在Unity中实现全局管理类?由于Unity脚本的运行机制和面向组件编程(COP)的思想,实现起来和普通的方式略有差别。

    第一种方式是使用静态类。适合存储一些全局的变量,如游戏当前关卡、玩家得分等。
    实现方式和普通的C#静态类没有差别。注意使用静态类就没有必要继承MonoBehaviour了。

    如果要实现复杂一些的全局控制,如切换游戏关卡等操作,更常用的方式是使用单例类。
    单例类的实现又分为两种:

    • 继承自MonoBehaviour的单例类
    • 纯C#的单例类

    前者的优点是:

    • 可以在Inspector中显示,便于赋值和查看变量等;
    • 可以利用MonoBehaviour的接口;
    • 可以使用Coroutine。
    • 等等。

    缺点也很多,主流的观点是能不继承MonoBehaviour就不要继承。

    纯C#的单例类

    实现起来简洁,易于理解。

    普通的写法,不考虑多线程

    public class MyClass
    {
        private static readonly MyClass _instance = new MyClass();
        public static Class Instance { 
        	get { 
        		return _instance; 
        	} 
        }    
     
        private MyClass() {}
    }
    
    

    线程安全的写法

    检查两次。C#中使用lock关键字。

    public class MyClass
    {
        private static volatile MyClass _instance;
        private static object _lock = new object();
     
        public static MyClass Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock(_lock)
                    {
                        if (_instance == null) 
                        	_instance = new MyClass();
                    }
                }
                return _instance;
            }
        }
     
        private MyClass() {}
    }
    
    

    基于MonoBehaviour的单例类

    普通的写法

    利用了Unity的运行机制,从Awake处获取Unity创建的对象作为单例。
    注意在Unity中不要使用new来创建MonoBehaviour实例。

    public class MyClass : MonoBehaviour
    {
    	static MyClass _instance;
    
    	void Awake () {
    		_instance = this;
    	}
    
    	public static MyClass Instance {
    		get {
    			// 不需要再检查变量是否为null
    			return _instance;
    		}
    	}
    }
    
    

    持久化的写法

    在多个场景中保存单例。又有两种方法。

    第一种是使用DontDestroyOnLoad方法,告诉Unity不要销毁实例所在的对象,然后将脚本挂到某个GameObject上:

    public class MyClass : MonoBehaviour
    {
    	static MyClass _instance;
    
    	void Awake () {
    		_instance = this;
    		// 防止载入新场景时被销毁
    		DontDestroyOnLoad(_instance.gameObject);	
    	}
    
    	public static MyClass Instance {
    		get {
    			return _instance;
    		}
    	}
    }
    
    

    上面这个方法有个弊端,必须要从挂载了这个单例的GameObject所在的场景启动,否则会找不到GameObject对象。但是开发和测试时我们经常会单独启动一个场景。

    另一种方法会创建一个GameObject,然后将单例挂载到其上:

    public class MyClass : MonoBehaviour {
     
        static MyClass _instance;
     
        static public MyClass Instance
        {
            get
            {
                if (_instance == null)
                {
                	// 尝试寻找该类的实例。此处不能用GameObject.Find,因为MonoBehaviour继承自Component。
                    _instance = Object.FindObjectOfType(typeof(MyClass)) as MyClass;
     
                    if (_instance == null)	// 如果没有找到
                    {                	                	
                        GameObject go = new GameObject("_MyClass");	// 创建一个新的GameObject
                        DontDestroyOnLoad(go);	// 防止被销毁
                        _instance = go.AddComponent<MyClass>();	// 将实例挂载到GameObject上
                    }
                }
                return _instance;
            }
        }
    }
    
    
  • 相关阅读:
    k8s 集群文件共享
    .net core 使用IOptionsXXX读取配置
    docker Dockerfile
    k8s 部署tomcatservice (NodePort通过节点向外提供服务)
    k8s 用Rinetd对外tomcatservice
    k8s 部署应用
    坑爹的matlab除法
    Cygwin/Git与Git Source Control Provider结合时初始目录
    手机电话号码从excel导入的最简单方法
    快捷方式改变电源计划,设置关闭显示器时间
  • 原文地址:https://www.cnblogs.com/CodeCabin/p/unity_global_manager.html
Copyright © 2020-2023  润新知