本文首發自inspoy的雜七雜八 | 菜雞inspoy的學習記錄php
以前一直在用cocos2d-x用c++寫代碼嘛,因此爲了開發方便本身設計了一套事件系統,如今轉到unity用c#了,就很天然地把以前那套東西搬過來用了XD
C#自帶的event其實就徹底能夠用,不過功能略顯簡陋,Unity自帶的EventSystem感受太複雜了,並且我又不太喜歡去操做editor,因此我仍是決定本身造輪子,弄一個最適合本身的事件機制html
事件機制基於觀察者模式,事件訂閱者向某個事件發佈者訂閱事件,綁定回調函數,事件發佈者發佈事件時會通知全部訂閱者,按訂閱順序依次調用他們預留的回調函數
三個類,SFEvent
(SF是前綴,啥意思你們也不用在乎233),SFEventData
,SFEventDispatcher
c++
類 | 做用 |
---|---|
SFEvent | 事件類 |
SFEventData | 事件所包含的數據 |
SFEventDispatcher | 事件發佈者 |
其中,事件類SFEvent
包含類型,事件數據SFEventData
,以及發佈者
不一樣事件的數據可能須要不一樣的數據結構,因此咱們抽象出一層接口ISFEventData
,實際使用的數據結構均繼承這個接口便可
下面貼出部分代碼(不完整,完整代碼見本文末尾)git
public class SFEvent
{
public string eventType; // 事件類型
public ISFEventData data; // 事件包含的自定義數據
public object target; // 事件發送者
// 如下是事件枚舉
public const string EVENT_TEST = "EVENT_TEST";
};
public interface ISFEventData
{
};複製代碼
全部事件數據的數據結構均繼承了ISFEventData
這個空接口,這樣一來不一樣的事件就能夠定製本身須要的事件數據結構了,若是時間數據很是簡單好比只有一個數字,我這裏也準備了一個通用的數據結構:github
public class SFSimpleEventData : ISFEventData
{
public object objVal = null;
public int intVal = 0;
public float floatVal = 0;
public string strVal = "";
}複製代碼
這個事件系統的核心部分,負責分發事件,管理訂閱
以前用cocos的時候習慣使用多繼承的方式來把dispatcher的功能加到一個類上,不過如今C#不支持多繼承了,因而就只能使用組合的方式,在類中儲存一個dispatcher類的實例來實現相似的效果。寫法會從this->dispatchEvent(e);
變成this.dispatcher.dispatchEvent(e);
使用C#的委託來實現訂閱,訂閱者傳遞這個委託類型的回調函數給發佈者便可:c#
public delegate void SFListenerSelector(SFEvent e);複製代碼
使用一個字典來管理不一樣的事件所各自對應的訂閱者數據結構
Dictionary<string, List<SFListenerSelector> > m_dictListener;複製代碼
訂閱者經過addEventListener
方法來訂閱一個事件:wordpress
public bool addEventListener(string eventType, SFListenerSelector sel) {
if (eventType != "" && sel != null) // 判斷有效性
{
if (hasEventListener(eventType, sel))
{
// SFUtils這個類是我本身弄的,下一篇文章再講
SFUtils.log(string.Format("重複監聽!type={0}", eventType));
}
if (!m_dictListeners.ContainsKey(eventType))
{
// 不存在的話就新建一個
List<SFListenerSelector> newSelectors = new List<SFListenerSelector>();
m_dictListeners[eventType] = newSelectors;
}
var selectors = m_dictListeners[eventType];
selectors.Add(sel);
return true;
}
return false;
}複製代碼
任何人均可以經過發佈者(一般來講是發佈者本身)來發布事件:函數
public int dispatchEvent(SFEvent e) {
int count = 0;
if (m_dictListeners.ContainsKey(e.eventType))
{
var selectors = m_dictListeners[e.eventType];
foreach (var item in selectors)
{
item(e);
count += 1;
}
}
return count;
}複製代碼
其實更常見的使用場景是在UI,我此次用的是Unity5自帶的UGUI,寫了一個控件來結合Unity的事件系統和我這個事件系統,實際開發的時候使用UI事件的方式和使用普通事件的方式是徹底一致的,這個咱們後面再詳細介紹學習
上面貼出的代碼片斷因爲篇幅限制只保留了關鍵部分,完整的代碼可在個人github上找到