Unity3D中利用Action实现本身的消息管理(订阅/发布)类

引言

通常的软件开发过程当中,为了方便对项目进行管理、维护和扩展,一般会采用一种MVC框架,以将显示逻辑、业务逻辑和数据进行分离。c#

这在传统企业软件的开发中很常见,但我在使用Unity作游戏开发的时候却几乎找不到相关框架。框架

其缘由猜想大概有两点,一是游戏开发模式多变,不一样类型的游戏代码结构差别很大,很难有一个适用性很强的框架出现;二是Unity太年轻,其大范围使用也不过是最近三四年的事情。ide

没有框架也不是意味着没有办法,MVC只是一种规范,只要在开发过程当中对代码的组织结构及用途作必定的约束,就能达到各层分离的效果。测试

在代码分层组织的结构中,出于解耦合的需求,一般须要一个对事件/消息进行管理的类,以便在各层之间传送消息,其功能包括事件/消息的订阅、发布以及取消订阅。spa

本文不会写怎么实现一个MVC结构(驾驭不了),只说说这个事件管理类的实现方法。3d

事件管理类的实现

一、编写EventManager类

一个事件管理类经过包括三个功能,订阅、发布消息、取消订阅,对应到代码中,也是就三个方法:AddEvent、DispatchEvent、RemoveEvent,还有一个字典List,对订阅事件作管理,实现以下:code

 

 1 /**  2 * UnityVersion: 2018.3.1f1  3 * FileName: EventManager.cs  4 * Author: TYQ  5 * CreateTime: 2019/04/04 15:49:53  6 * Description: 自定义的事件派发类  7 */
 8 using System;  9 using System.Collections;  10 using System.Collections.Generic;  11 using UnityEngine;  12 
 13 public class EventManager  14 {  15     /// <summary>
 16     /// 带返回参数的回调列表,参数类型为T,支持一对多  17     /// </summary>
 18     public static Dictionary<string, List<Delegate>> events = new Dictionary<string, List<Delegate>>();  19 
 20     /// <summary>
 21     /// 注册事件,1个返回参数  22     /// </summary>
 23     /// <param name="eventName"></param>
 24     /// <param name="callback"></param>
 25     public static void AddEvent<T> (string eventName, Action<T> callback)  26  {  27         List<Delegate> actions = null;  28 
 29         //eventName已存在
 30         if (events.TryGetValue(eventName, out actions))  31  {  32  actions.Add(callback);  33  }  34         //eventName不存在
 35         else
 36  {  37             actions = new List<Delegate>();  38 
 39  actions.Add(callback);  40  events.Add(eventName ,actions);  41  }  42  }  43 
 44     /// <summary>
 45     /// 注册事件,不带返回参数  46     /// </summary>
 47     /// <param name="eventName"></param>
 48     /// <param name="callback"></param>
 49     public static void AddEvent(string eventName, Action callback)  50  {  51         List<Delegate> actions = null;  52 
 53         //eventName已存在
 54         if (events.TryGetValue(eventName, out actions))  55  {  56  actions.Add(callback);  57  }  58         //eventName不存在
 59         else
 60  {  61             actions = new List<Delegate>();  62 
 63  actions.Add(callback);  64  events.Add(eventName, actions);  65  }  66  }  67 
 68     /// <summary>
 69     /// 移除事件  70     /// </summary>
 71     /// <param name="eventName"></param>
 72     /// <param name="callback"></param>
 73     public static void RemoveEvent<T>(string eventName, Action<T> callback)  74  {  75         List<Delegate> actions = null;  76 
 77         if (events.TryGetValue(eventName, out actions))  78  {  79  actions.Remove(callback);  80             if (actions.Count == 0)  81  {  82  events.Remove(eventName);  83  }  84  }  85  }  86     /// <summary>
 87     /// 移除所有事件  88     /// </summary>
 89     public static void RemoveAllEvents ()  90  {  91  events.Clear();  92  }  93 
 94     /// <summary>
 95     /// 派发事件  96     /// </summary>
 97     /// <param name="eventName"></param>
 98     /// <param name="arg"></param>
 99     public static void DispatchEvent<T>(string eventName, T arg) 100  { 101         List<Delegate> actions = null; 102 
103         if (events.ContainsKey(eventName)) 104  { 105             events.TryGetValue(eventName, out actions); 106 
107             foreach (var act in actions) 108  { 109  act.DynamicInvoke(arg); 110  } 111  } 112  } 113     /// <summary>
114     /// 派发事件,不带参数 115     /// </summary>
116     /// <param name="eventName"></param>
117     /// <param name="arg"></param>
118     public static void DispatchEvent(string eventName) 119  { 120         List<Delegate> actions = null; 121 
122         if (events.ContainsKey(eventName)) 123  { 124             events.TryGetValue(eventName, out actions); 125 
126             foreach (var act in actions) 127  { 128  act.DynamicInvoke(); 129  } 130  } 131  } 132 }
EventManager.cs

 

二、测试事件类

2.一、先制做测试界面,包括两个接收(订阅)消息的Text组件,以及一个发布消息的Slider组件,层次结构见下图:orm

 预期效果:拖动Slider,Slider的值会同步显示到两个用于接收的Text组件上。blog

2.二、编写测试类游戏

 先写一个发布消息的类,在Slider的onValueChanged事件中执行发布操做,以下

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Sender : MonoBehaviour { public Slider slider = null; private void Awake() { slider.onValueChanged.AddListener(delegate (float value) { Debug.LogFormat("slider:{0}", value); //有参分发
            EventManager.DispatchEvent<float>("NumberEvent", value); //无参分发
            EventManager.DispatchEvent("NumberEventNoParam"); }); } }
Sender.cs

 再写一下接收消息的类,,以下

using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Receiver : MonoBehaviour { public Text receiveText1 = null; public Text receiveText2 = null; private void Awake() { //带参数回调 //注册方法1
        EventManager.AddEvent<float>("NumberEvent", OnNumberChangeEventHandler); //注册方法2
        EventManager.AddEvent("NumberEvent", delegate (float arg) { receiveText2.text = (Convert.ToInt32(arg)).ToString(); }); //无参回调
        EventManager.AddEvent("NumberEventNoParam", delegate () { Debug.Log("无参回调"); }); } /// <summary>
    /// 事件处理方法 /// </summary>
    /// <param name="arg"></param>
    private void OnNumberChangeEventHandler (float arg) { receiveText1.text = (Convert.ToInt32(arg)).ToString(); } }
Receiver.cs

 2.三、运行

运行结果以下图:

能够看到,Slider值的改变会立马同步到接收端Text中,实现了预期的功能。

 

 三、后记

一、我在EventManager.cs中使用Action类型来接受事件的回调,而不是使用c#的delegate,是由于,Action是Unity已经定义好的一种公共delegate,使用起来更方便。

二、目录的EventManager.cs只支持无参回调和一个参数的回调,如需更多参数回调,能够依照AddEvent<T>的写法,添加剧载。

三、在EventManager.cs中好像还缺一个无参的RemoveEvent方法,请自行补充。

 

 四、补充(2019-04-22)

实际使用中发现,派发消息时,传递两个参数和三个参数的状况仍是挺多的,所以对EventManager进行了补充,有些不优雅的地方也进行了修改:

 1 /**  2 * UnityVersion: 2018.3.1f1  3 * FileName: EventManager.cs  4 * Author: TYQ  5 * CreateTime: 2019/04/04 15:49:53  6 * Description: 自定义的事件派发类  7 */
 8 using System;  9 using System.Collections;  10 using System.Collections.Generic;  11 using UnityEngine;  12 
 13 public class EventManager  14 {  15     /// <summary>
 16     /// 带返回参数的回调列表,参数类型为T,支持一对多  17     /// </summary>
 18     public static Dictionary<string, List<Delegate>> events = new Dictionary<string, List<Delegate>>();  19 
 20     /// <summary>
 21     /// 通用注册事件方法  22     /// </summary>
 23     /// <param name="eventName"></param>
 24     /// <param name="callback"></param>
 25     private static void CommonAdd (string eventName, Delegate callback)  26  {  27         List<Delegate> actions = null;  28 
 29         //eventName已存在
 30         if (events.TryGetValue(eventName, out actions))  31  {  32  actions.Add(callback);  33  }  34         //eventName不存在
 35         else
 36  {  37             actions = new List<Delegate>();  38 
 39  actions.Add(callback);  40  events.Add(eventName, actions);  41  }  42  }  43 
 44     /// <summary>
 45     /// 注册事件,0个返回参数  46     /// </summary>
 47     /// <param name="eventName"></param>
 48     /// <param name="callback"></param>
 49     public static void AddEvent(string eventName, Action callback)  50  {  51  CommonAdd(eventName, callback);  52  }  53 
 54     /// <summary>
 55     /// 注册事件,1个返回参数  56     /// </summary>
 57     /// <param name="eventName"></param>
 58     /// <param name="callback"></param>
 59     public static void AddEvent<T> (string eventName, Action<T> callback)  60  {  61  CommonAdd(eventName, callback);  62  }  63     /// <summary>
 64     /// 注册事件,2个返回参数  65     /// </summary>
 66     /// <param name="eventName"></param>
 67     /// <param name="callback"></param>
 68     public static void AddEvent<T, T1>(string eventName, Action<T, T1> callback)  69  {  70  CommonAdd(eventName, callback);  71  }  72     /// <summary>
 73     /// 注册事件,3个返回参数  74     /// </summary>
 75     /// <param name="eventName"></param>
 76     /// <param name="callback"></param>
 77     public static void AddEvent<T, T1, T2>(string eventName, Action<T, T1, T2> callback)  78  {  79  CommonAdd(eventName, callback);  80  }  81 
 82     /// <summary>
 83     /// 通用移除事件的方法  84     /// </summary>
 85     /// <param name="eventName"></param>
 86     /// <param name="callback"></param>
 87     private static void CommonRemove (string eventName, Delegate callback)  88  {  89         List<Delegate> actions = null;  90 
 91         if (events.TryGetValue(eventName, out actions))  92  {  93  actions.Remove(callback);  94             if (actions.Count == 0)  95  {  96  events.Remove(eventName);  97  }  98  }  99  } 100 
101     /// <summary>
102     /// 移除事件 0参数 103     /// </summary>
104     /// <param name="eventName"></param>
105     /// <param name="callback"></param>
106     public static void RemoveEvent(string eventName, Action callback) 107  { 108  CommonRemove(eventName, callback); 109  } 110 
111     /// <summary>
112     /// 移除事件 1个参数 113     /// </summary>
114     /// <param name="eventName"></param>
115     /// <param name="callback"></param>
116     public static void RemoveEvent<T>(string eventName, Action<T> callback) 117  { 118  CommonRemove(eventName, callback); 119  } 120 
121     /// <summary>
122     /// 移除事件 2个参数 123     /// </summary>
124     /// <param name="eventName"></param>
125     /// <param name="callback"></param>
126     public static void RemoveEvent<T, T1>(string eventName, Action<T, T1> callback) 127  { 128  CommonRemove(eventName, callback); 129  } 130     /// <summary>
131     /// 移除事件 3个参数 132     /// </summary>
133     /// <param name="eventName"></param>
134     /// <param name="callback"></param>
135     public static void RemoveEvent<T, T1, T2>(string eventName, Action<T, T1, T2> callback) 136  { 137  CommonRemove(eventName, callback); 138  } 139 
140     /// <summary>
141     /// 移除所有事件 142     /// </summary>
143     public static void RemoveAllEvents () 144  { 145  events.Clear(); 146  } 147 
148     /// <summary>
149     /// 派发事件,0参数 150     /// </summary>
151     /// <param name="eventName"></param>
152     /// <param name="arg"></param>
153     public static void DispatchEvent(string eventName) 154  { 155         List<Delegate> actions = null; 156 
157         if (events.ContainsKey(eventName)) 158  { 159             events.TryGetValue(eventName, out actions); 160 
161             foreach (var act in actions) 162  { 163  act.DynamicInvoke(); 164  } 165  } 166  } 167 
168     /// <summary>
169     /// 派发事件 1个参数 170     /// </summary>
171     /// <param name="eventName"></param>
172     /// <param name="arg"></param>
173     public static void DispatchEvent<T>(string eventName, T arg) 174  { 175         List<Delegate> actions = null; 176 
177         if (events.ContainsKey(eventName)) 178  { 179             events.TryGetValue(eventName, out actions); 180 
181             foreach (var act in actions) 182  { 183  act.DynamicInvoke(arg); 184  } 185  } 186  } 187 
188     /// <summary>
189     /// 派发事件 2个参数 190     /// </summary>
191     /// <param name="eventName">事件名</param>
192     /// <param name="arg">参数1</param>
193     /// <param name="arg2">参数2</param>
194     public static void DispatchEvent<T, T1>(string eventName, T arg, T1 arg2) 195  { 196         List<Delegate> actions = null; 197 
198         if (events.ContainsKey(eventName)) 199  { 200             events.TryGetValue(eventName, out actions); 201 
202             foreach (var act in actions) 203  { 204  act.DynamicInvoke(arg, arg2); 205  } 206  } 207  } 208 
209     /// <summary>
210     /// 派发事件 3个参数 211     /// </summary>
212     /// <param name="eventName">事件名</param>
213     /// <param name="arg">参数1</param>
214     /// <param name="arg2">参数2</param>
215     /// <param name="arg3">参数3</param>
216     public static void DispatchEvent<T1, T2, T3>(string eventName, T1 arg, T2 arg2, T3 arg3) 217  { 218         List<Delegate> actions = null; 219 
220         if (events.ContainsKey(eventName)) 221  { 222             events.TryGetValue(eventName, out actions); 223 
224             foreach (var act in actions) 225  { 226  act.DynamicInvoke(arg, arg2, arg3); 227  } 228  } 229  } 230 }
EventManager
相关文章
相关标签/搜索