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