Unity事件中心機(jī)制

在游戲開發(fā)中牵敷,為了降低各個模塊之間的耦合度析显,常常會采用屬性改變時候觸發(fā)某個事件來通知其他的物體碴里,而其他物體響應(yīng)到這個事件缺脉,進(jìn)而改變自身的狀態(tài)。而為了方便管理劳秋,會寫一個事件中心來集中管理事件的注冊和觸發(fā)仓手。

先看一下事件中心機(jī)制的大體設(shè)計思路:

類設(shè)計圖.png
  • EventCenter:事件中心,提供了事件的注冊玻淑、取消注冊嗽冒、分發(fā)事件等功能
  • Events:事件的基類,標(biāo)記事件類型

下面是一個簡單EventCenter的寫法

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace EventSystem
{
    public static class EventCenter
    {
        // 事件字典
        private static Dictionary<int, LinkedList<Action<Events>>> es = new Dictionary<int, LinkedList<Action<Events>>>();


        public static void Register<T>(Action<Events> events) where T : Events<T>,new()
        {
            Register(Events<T>.Id, events);
        }

        private static void Register(int id, Action<Events> events)
        {
            if (events == null)
            {
                return;
            }
            if (!es.ContainsKey(id))
            {
                es.Add(id, new LinkedList<Action<Events>>());
            }
            if (!es[id].Contains(events))
            {
                es[id].AddLast(events);
            }
        }


        public static void UnRegister<T>(Action<Events> events)where T : Events<T>, new()
        {
            UnRegister(Events<T>.Id, events);
        }

        private static void UnRegister(int id, Action<Events> events)
        {
            if (!es.ContainsKey(id))
            {
                return;
            }
            es[id].Remove(events);
        }

        public static void UnRegister(Action<Events> events)
        {
            if (events == null)
            {
                return;
            }   
            foreach (LinkedList<Action<Events>> item in es.Values)
            {
                item.Remove(events);
            }
        }

        public static void Trigger<T>(T t) where T : Events<T>, new()
        {
            int id = Events<T>.Id;
            if (es.ContainsKey(id))
            {
                foreach (var item in es[id])
                {
                    item?.Invoke(t);
                }
            }
        }

        /// <summary>
        /// 清理字典中無人監(jiān)聽的事件id
        /// </summary>
        public static void Clean()
        {
            foreach (var item in es)
            {
                if (item.Value.Count == 0)
                {
                    es.Remove(item.Key);
                }
            }
        }

        /// <summary>
        /// 清理某個事件的所有監(jiān)聽者
        /// </summary>
        /// <param name="id">事件Id</param>
        public static void Clean(int Id)
        {
            es.Remove(Id);
        }

        /// <summary>
        ///  清除所有id和監(jiān)聽者
        /// </summary>
        public static void Clear()
        {
            es.Clear();
        }
    }
}

再寫一個事件基類及其派生類:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace EventSystem
{
    public abstract class Events
    {
        public object sender;

        //別名
        public string Alias { get; set; } = "default";
    }

    public abstract class Events<T> : Events where T : Events<T>, new()
    {
        private static int _id = 0;
        public static int Id
        {
            get
            {
                if (_id == 0)
                {
                    _id = typeof(T).GetHashCode();
                }
                return _id;
            }
        }

    }
}

之后是優(yōu)化方面补履,為了減少頻繁的new Events()導(dǎo)致的GC問題添坊,構(gòu)建了一個EventHelper類來緩存事件(應(yīng)該有坑,為了盡可能的減少坑箫锤,我又在事件Events上添加一個Alias屬性帅腌,用來為Events實例來指定一個別名,事件發(fā)送者在獲取事件的時候根據(jù)別名+類型來獲取麻汰,以減少出現(xiàn)意想不到的坑)速客。為了不會出現(xiàn)坑,還是使用new Events()更保險一點

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace EventSystem
{
    /// <summary>
    /// 用來緩存具體事件 -主要是為了少new事件五鲫,0GC或者減少GC
    /// </summary>
    public static class EventsHelper
    {

        private static List<Events> pools = new List<Events>();

        public static int Count { get { return pools.Count; } }
    
        /// <summary>
        /// 獲取事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="alias">事件標(biāo)記</param>
        /// <returns></returns>
        public static T GetEvents<T>(string alias, object sender = null) where T : Events<T>, new()
        {
            T t = null;
            for (int i = 0, len = pools.Count; i < len; i++)
            {
                if (pools[i] is T && pools[i].Alias == alias)
                {
                    t = pools[i] as T;
                    break;
                }
            }
            if (t == null)
            {
                t = new T { Alias = alias };
                pools.Add(t);
            }

            t.sender = sender;
            return t;
        }
    }
}

之后是一個測試的腳本溺职,隨便掛到一個GameObject上,就可以看到效果

using System;
using System.Collections;
using System.Collections.Generic;
using EventSystem;
using UnityEngine;


// demo
public class AEvents : Events<AEvents>
{
    // 事件參數(shù)
    public string EventName = "A";

}

public class BEvents : Events<BEvents>
{
    // 事件參數(shù)
    public string EventName = "B";

}

public class EventSystemDemo : MonoBehaviour
{

    private void Awake()
    {
        EventCenter.Register<AEvents>(OnAEvents);
        EventCenter.Register<BEvents>(OnBEvents);

        //EventCenter.UnRegister<AEvents>(OnAEvents);
    }

    private void Start()
    {
        EventCenter.Trigger(EventsHelper.GetEvents<AEvents>("A", this));
        // 或者
        // EventCenter.Trigger(new AEvents() { sender = this, EventName = "A" });
        EventCenter.Trigger(EventsHelper.GetEvents<BEvents>("B", this));

        Debug.Log("EventHelper Count: " + EventsHelper.Count);
    }

    private void OnBEvents(Events obj)
    {
        BEvents ae = obj as BEvents;
        Debug.LogError("EventB {sender:" + ae.sender.ToString() + "  args:" + ae.EventName);
    }

    private void OnAEvents(Events obj)
    {
        AEvents ae = obj as AEvents;
        Debug.LogError("EventA {sender:" + ae.sender.ToString() + "  args:" + ae.EventName);
    }
}

.
ok位喂,第一次寫簡書浪耘,不知道寫點啥,自己也是個大坑塑崖,就這樣吧

等等七冲,按照慣例,最后還要留種规婆。澜躺。蝉稳。
鏈接:https://pan.baidu.com/s/1da5TNmk0HjDVnaFnfhjZuQ
提取碼:lee2

(煢煢無依擼代碼,無可奈何負(fù)韶華熬虮伞)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末耘戚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子操漠,更是在濱河造成了極大的恐慌收津,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浊伙,死亡現(xiàn)場離奇詭異撞秋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嚣鄙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門部服,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拗慨,你說我怎么就攤上這事廓八。” “怎么了赵抢?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵剧蹂,是天一觀的道長。 經(jīng)常有香客問我烦却,道長宠叼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任其爵,我火速辦了婚禮冒冬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘摩渺。我一直安慰自己简烤,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布摇幻。 她就那樣靜靜地躺著横侦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绰姻。 梳的紋絲不亂的頭發(fā)上枉侧,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機(jī)與錄音狂芋,去河邊找鬼榨馁。 笑死,一個胖子當(dāng)著我的面吹牛帜矾,可吹牛的內(nèi)容都是我干的翼虫。 我是一名探鬼主播屑柔,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蛙讥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灭衷,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤次慢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后翔曲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迫像,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年瞳遍,在試婚紗的時候發(fā)現(xiàn)自己被綠了闻妓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡掠械,死狀恐怖由缆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猾蒂,我是刑警寧澤均唉,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站肚菠,受9級特大地震影響舔箭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚊逢,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一层扶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烙荷,春花似錦镜会、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拿诸,卻和暖如春扒袖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亩码。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工季率, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人描沟。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓飒泻,卻偏偏與公主長得像鞭光,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泞遗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350