用unity做网游的同学应该不少,其中一个很蛋疼的问题就是主线程中尤其是UI部分很多实例都是不允许子线程修改的,那么我们就只有想办法把这些子线程里的数据缓存起来,让主线程自己拿着这些数据该干嘛干嘛去。
使用方法很简单,在随便哪个Monobehaviour脚本里的Update函数里调用EventDispatcher.Instance().OnTick();就可以了。
例:
需要派发事件时:
eventValue可以是任何类型的数据。
在需要的地方监听事件:
其中EventCallback是一个参数为EventBase的函数:
进阶用法:
细心的同学应该发现了,EventDispatcher类的最下面有个ChatEvent,
调用
在监听函数里
酱紫,就可以很方便取出自定义的事件中的多个参数了~
废话少说,先上源码。
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()
{
}
}
|
例:
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);
|
在需要的地方监听事件:
1
|
EventDispatcher.Instance().RegistEventListener(
"EventName"
,EventCallback );
|
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;
}
|