用Unity作個遊戲(二) - 事件系統

本文首發自inspoy的雜七雜八 | 菜雞inspoy的學習記錄php

前言

以前一直在用cocos2d-x用c++寫代碼嘛,因此爲了開發方便本身設計了一套事件系統,如今轉到unity用c#了,就很天然地把以前那套東西搬過來用了XD
C#自帶的event其實就徹底能夠用,不過功能略顯簡陋,Unity自帶的EventSystem感受太複雜了,並且我又不太喜歡去操做editor,因此我仍是決定本身造輪子,弄一個最適合本身的事件機制html

設計

事件機制基於觀察者模式,事件訂閱者向某個事件發佈者訂閱事件,綁定回調函數,事件發佈者發佈事件時會通知全部訂閱者,按訂閱順序依次調用他們預留的回調函數
三個類,SFEvent(SF是前綴,啥意思你們也不用在乎233),SFEventDataSFEventDispatcherc++

做用
SFEvent 事件類
SFEventData 事件所包含的數據
SFEventDispatcher 事件發佈者

SFEvent

其中,事件類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
{
};複製代碼

SFEventData

全部事件數據的數據結構均繼承了ISFEventData這個空接口,這樣一來不一樣的事件就能夠定製本身須要的事件數據結構了,若是時間數據很是簡單好比只有一個數字,我這裏也準備了一個通用的數據結構:github

public class SFSimpleEventData : ISFEventData
{
    public object objVal = null;
    public int intVal = 0;
    public float floatVal = 0;
    public string strVal = "";
}複製代碼

SFEventDispatcher

這個事件系統的核心部分,負責分發事件,管理訂閱
以前用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上找到

相關文章
相關標籤/搜索