注:25年2月24日进行补充 这篇文章介绍一下公共Mono模块。
为什么有公共Mono模块?
很多时候我们写代码,不想继承MonoBehaviour类(比如减少性能开销、简化代码量,MonoBehaviour),但又想用MonoBehaviour里Update、Start等方法。这时候就需要搭建公共Mono模块来实现我们的需求了。
思路
以实现Update为例,既然我们知道,不继承MonoBehaviour类的不能直接调用Update等方法,那么有没有什么办法、把我们的方法塞到update里呢?
答案是有的,这里有个知识点是“委托和事件”,我们可以把我们的方法、塞到委托里,在继承Mono的脚本里调用这个委托就可以了。
下面第一种是跟着唐老狮写得,写了两个脚本,但个人不太喜欢这种,觉得比较臃肿,写成一个脚本就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 using UnityEngine.Events; public class MonoController : MonoBehaviour { //我创建两个事件,目的是提高安全性 private event UnityAction UnityStart; private event UnityAction UnityUpdate; //调用委托 private void Start() { if(UnityStart != null) UnityStart(); } private void Update() { if(UnityUpdate != null) UnityUpdate(); } //开始写我们的函数 public void AddStart(UnityAction action) { UnityStart += action; UnityStart.invoke()//因为我们想添加后立即执行,Unity默认只执行一次 } public void AddUpdate(UnityAction action) { UnityUpdate += action; } public void RemoveStart(UnityAction action) { UnityStart -= action; } public void RemoveUpdate(UnityAction action) { UnityUpdate -= action; } }
以上就是我们写的一个Mono控制器,接下来我们还需要写一个Mono管理器,既然是管理器我们肯定要继承单例模式基类脚本。管理器接收命令、分发到控制器执行。于是我创建个MonoMgr.cs的脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 using UnityEngine.Events; public class MonoMgr : SingletonBase<MonoMgr> { //私有化一个控制器,写构造函数 private MonoController controller; public MonoMgr() { GameObject obj = new GameObject("MonoController"); controller = obj.AddComponent<MonoController>(); } //书写函数,我们加入的委托会在控制器执行 public void AddStart(UnityAction action) { controller.AddStart(action); } public void AddUpdate(UnityAction action) { controller.AddUpdate(action); } public void RemoveStart(UnityAction action) { controller.RemoveStart(action); } public void RemoveUpdate(UnityAction action) { controller.RemoveUpdate(action); } }
接下来举个例子如何调用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 //我们没继承MonoBehaviour public class Test1 { public void Update() { Debug.Log("示例"); } } public class Test : MonoBehaviour { void Start() { Test1 t = new Test1; MonoMgr.GetInstance().AddUpdate(t.Update); //上面是一个单例里添加方法 } }
于是我又把这两个脚本写成一个,感觉很简洁了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Events; public class MonoManager : SingleMono<MonoManager> { //私有化一个控制器,写构造函数 public event UnityAction onStart; public event UnityAction onUpdate; public event UnityAction onLateUpdate; public event UnityAction onFixedUpdate; // Start is called before the first frame update void Start() { onStart?.Invoke(); } // Update is called once per frame void Update() { onUpdate?.Invoke(); } private void LateUpdate() { onLateUpdate?.Invoke(); } private void FixedUpdate() { onFixedUpdate?.Invoke(); } //方法 public void AddStart(UnityAction action) { onStart += action; onStart.invoke()//因为我们想添加后立即执行,Unity默认只执行一次 } public void AddUpdate(UnityAction action) { onUpdate += action; } public void AddLateUpdate(UnityAction action) { onLateUpdate += action; } public void AddFixedUpdate(UnityAction action) { onFixedUpdate += action; } //清空方法 public void RemoveStart(UnityAction action) { onStart -= action; } public void RemoveUpdate(UnityAction action) { onUpdate -= action; } public void RemoveFixedUpdate(UnityAction action) { onFixedUpdate -= action; } public void RemoveLateUpdate(UnityAction action) { onLateUpdate -= action; } }