基于Unity的多线程之间的事件派发

用unity做网游的同学应该不少,其中一个很蛋疼的问题就是主线程中尤其是UI部分很多实例都是不允许子线程修改的,那么我们就只有想办法把这些子线程里的数据缓存起来,让主线程自己拿着这些数据该干嘛干嘛去。

废话少说,先上源码。


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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using System.Threading;
  
public class EventDispatcher
{
     private static EventDispatcher sinstance;
     public static EventDispatcher Instance()
     {
         if (sinstance == null )
         {
             sinstance = new EventDispatcher();
         }
         return sinstance;
     }
//  object m_objLock = new object();
//  object m_objLock2 = new object();
  
     public delegate void EventCallback(EventBase eb);
  
     private Dictionary<string, List<EventCallback>> registedCallbacks = new Dictionary<string, List<EventCallback>>();
     private Dictionary<string, List<EventCallback>> registedCallbacksPending = new Dictionary<string, List<EventCallback>>();
     private List<EventBase> lPendingEvents = new List<EventBase>();
     public void RegistEventListener(string sEventName, EventCallback eventCallback)
     {
         lock ( this )
         {
             if (!registedCallbacks.ContainsKey(sEventName))
             {
                 registedCallbacks.Add(sEventName, new List<EventCallback>());
             }
  
             if (isEnuming)
             {
                 if (!registedCallbacksPending.ContainsKey(sEventName))
                 {
                     registedCallbacksPending.Add(sEventName, new List<EventCallback>());
                 }
                 registedCallbacksPending[sEventName].Add(eventCallback);
                 return ;
             }
  
             registedCallbacks[sEventName].Add(eventCallback);
         }
     }
     public void UnregistEventListener(string sEventName, EventCallback eventCallback)
     {
         lock ( this )
         {
             if (!registedCallbacks.ContainsKey(sEventName))
             {
                 return ;
             }
  
             if (isEnuming)
             {
                 Debug.Log( "Cannot unregist event this moment!" );
                 return ;
             }
  
             registedCallbacks[sEventName].Remove(eventCallback);
         }
     }
  
     List<EventBase> lEvents = new List<EventBase>();
     public void DispatchEvent<T>(T eventInstance)
         where T:EventBase
     {
         lock ( this )
         {
             if (!registedCallbacks.ContainsKey(eventInstance.sEventName))
             {
                 return ;
             }
  
             if (isEnuming)
             {
                 lPendingEvents.Add(eventInstance);
                 Debug.Log( "Cannot dispatch event this moment!" );
                 return ;
             }
  
             foreach (EventBase eb in lPendingEvents)
             {
                 lEvents.Add(eb);
             }
             lPendingEvents.Clear();
  
             lEvents.Add(eventInstance);
         }
     }
     public void DispatchEvent(string eventName, object eventValue)
     {
         lock ( this )
         {
             if (!registedCallbacks.ContainsKey(eventName))
             {
                 return ;
             }
  
             if (isEnuming)
             {
                 lPendingEvents.Add( new EventBase(eventName, eventValue));
                 Debug.Log( "Cannot dispatch event this moment!" );
                 return ;
             }
  
             lEvents.Add( new EventBase(eventName, eventValue));
         }
     }
  
     private void testPendingEvents()
     {
         foreach (EventBase eb in lPendingEvents)
         {
             lEvents.Add(eb);
         }
         lPendingEvents.Clear();
     }
  
     public static bool isEnuming = false ;
     public void OnTick()
     {
         lock ( this )
         {
             if (lEvents.Count == 0)
             {
                 foreach (string sEventName in registedCallbacksPending.Keys)
                 {
                     foreach (EventCallback ec in registedCallbacksPending[sEventName])
                     {
                         RegistEventListener(sEventName, ec);
                     }
                 }
                 registedCallbacksPending.Clear();
  
                 testPendingEvents();
                 return ;
             }
  
             isEnuming = true ;
             foreach (EventBase eb in lEvents)
             {
                 for ( int i = 0;i<registedCallbacks[eb.sEventName].Count;i++) // EventCallback ecb in registedCallbacks[eb.sEventName])
                 {
                     EventCallback ecb = registedCallbacks[eb.sEventName][i];
                     if (ecb == null )
                     {
                         continue ;
                     }
                     ecb(eb);
                 }
             }
             lEvents.Clear();
         }
         isEnuming = false ;
     }
}
  
public class EventBase
{
     public object eventValue;
     public string sEventName;
     public EventBase()
     {
         sEventName = this .GetType().FullName;
     }
     public EventBase(string eventName, object ev)
     {
         eventValue = ev;
         sEventName = eventName;
     }
}
  
public class ChatEvent : EventBase
{
     public int iChannel;
     public string sContent;
     public string sName;
  
     public ChatEvent()
     {
     }
}
使用方法很简单,在随便哪个Monobehaviour脚本里的Update函数里调用EventDispatcher.Instance().OnTick();就可以了。
例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using UnityEngine;
using System.Collections;
  
public class EventTicker : MonoBehaviour
{
     void Start()
     {
     }
  
     void Update()
     {
  
         EventDispatcher.Instance().OnTick();
     }
}
需要派发事件时:
1
EventDispatcher.Instance().DispatchEvent( "EventName" , eventValue);
eventValue可以是任何类型的数据。
在需要的地方监听事件:
1
EventDispatcher.Instance().RegistEventListener( "EventName" ,EventCallback );
其中EventCallback是一个参数为EventBase的函数:
1
2
3
4
void EventCallback(EventBase eb)
{
Debug.Log( "EventCallback:" + eb.eventValue.ToString());
}
进阶用法:
细心的同学应该发现了,EventDispatcher类的最下面有个ChatEvent,
1
public class ChatEvent : EventBase
调用
1
2
ChatEvent ce = new ChatEvent();
EventDispatcher.Instance().DispatchEvent<ChatEvent>(ce);
在监听函数里
1
2
3
4
void chatCallBack(EventBase eb)
     {
         ChatEvent ce = eb as ChatEvent;
}
酱紫,就可以很方便取出自定义的事件中的多个参数了~
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值