用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;} |
本文提供了一种在Unity游戏中处理主线程与子线程间数据交互的方法,通过实现事件分发器,使得主线程能够独立于子线程操作特定数据,解决主线程中UI部分不允许子线程修改的问题。文中详细介绍了如何注册事件监听、分发事件以及在不同场景下应用此方案,包括如何使用自定义事件类型和监听函数提取事件参数。
328

被折叠的 条评论
为什么被折叠?



