事件系统的好处很多,最主要的还是能够最大限度的降低模块间的耦合度,这里实现一个很简单的事件管理系统,主要功能就是对事件进行分发,以达到解偶的目的。事件系统很多新手好像不太适应,但是用的多了,就会发现它的神奇之处。


直接上代码:

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

public class EventManager : MonoBehaviour
{
Dictionary<EventID, List<EventObserver>> observerList = new Dictionary<EventID, List<EventObserver>>();
Queue eventQueue = new Queue(); //消息队列
private static EventManager _instance = null;
public static EventManager instance()
{
return _instance;
}
void Awake()
{
Debug.Log("===========启动消息系统===========");
_instance = this;
}
void Update()
{
while (eventQueue.Count > 0)
{
EventData eve = (EventData)eventQueue.Dequeue();
if (!observerList.ContainsKey(eve.eid))
{
continue;
}
List<EventObserver> observers = observerList[eve.eid];
for (int i = 0; i < observers.Count; i++)
{
if (observers[i] == null) continue;
observers[i].HandleEvent(eve);
}
}
}
//发送事件
public void SendEvent(EventData eve)
{
eventQueue.Enqueue(eve);
}
//添加监听者
void RegisterObj(EventObserver newobj, EventID eid)
{
if (!observerList.ContainsKey(eid))
{
List<EventObserver> list = new List<EventObserver>();
list.Add(newobj);
observerList.Add(eid, list);
}
else
{
List<EventObserver> list = observerList[eid];
foreach (EventObserver obj in list)
{
if (obj == newobj)
{
return;
}
}
list.Add(newobj);
}
}
//移除监听者
void RemoveObj(EventObserver removeobj)
{
foreach (KeyValuePair<EventID, List<EventObserver>> kv in observerList)
{
List<EventObserver> list = kv.Value;
foreach (EventObserver obj in list)
{
if (obj == removeobj)
{
list.Remove(obj);
break;
}
}
}
}
/// <summary>
/// 移除一个监听者
/// </summary>
/// <returns>The remove.</returns>
/// <param name="removeobj">Removeobj.</param>
public static void Remove(EventObserver removeobj)
{
if (EventManager.instance() == null) return;
EventManager.instance().RemoveObj(removeobj);
}
/// <summary>
/// 监听者在这里注册
/// </summary>
/// <returns>The register.</returns>
/// <param name="newobj">Newobj.</param>
/// <param name="eids">需要监听的事件列表.</param>
public static void Register(EventObserver newobj, params EventID[] eids)
{
if (EventManager.instance() == null) return;
foreach (EventID eid in eids)
{
EventManager.instance().RegisterObj(newobj, eid);
}
}
}

EventManager必须要挂载到unity物体上,并且不能被销毁。这里应该也可以独立开启一个线程来进行消息的分发,但是应该会更复杂一些,因为涉及到线程间的数据处理。以后有机会我也会实现一下。

提供给用户访问的就2个静态方法,注册和注销监听者。

我们还需要定义事件id,这里用枚举来实现:

public enum EventID
{
EVENT_1 = 10001,
EVENT_2 = 10002,
}

实现消息的实体:

public class EventData
{
public EventID eid;
public EventData(EventID eid)
{
this.eid = eid;
}

public void Send()
{
if (EventManager.instance() != null) EventManager.instance().SendEvent(this);
}
public static EventData CreateEvent(EventID eventid)
{
EventData data = new EventData(eventid);
return data;
}
}
public class Event1 : EventData
{
public int t1 { get; private set; }
public int t2 { get; private set; }
public string s1 { get; private set; }
public Event1(int t1, int t2, string s1) : base(EventID.EVENT_1)
{
this.t1 = t1;
this.t2 = t2;
this.s1 = s1;
}
}

这里EventData是基础的消息类,一些不需要参数的消息可以直接使用,下面我们还实现的一个Event1,代参数的消息,所有消息都需要继承EventData类。


接下来我们还需要定义一个监听者用来接收消息的接口:

public interface EventObserver
{
void HandleEvent(EventData resp);
}

所有的监听者都要实现HandleEvent方法。


下面我们来看一下如何接收和发送消息,创建脚本EventTest:

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

public class EventTest : MonoBehaviour, EventObserver
{
public string uname = "aaa";
public string password = "bbb";

void Start()
{
EventManager.Register(this, EventID.EVENT_1, EventID.EVENT_2);
}

void OnGUI()
{
if (GUI.Button(new Rect(10, 10, 150, 50), "send eve1"))
{
Event1 eve = new Event1(1, 2, "123");
eve.Send();
}
if (GUI.Button(new Rect(10, 70, 150, 50), "send eve2"))
{
EventData.CreateEvent(EventID.EVENT_2).Send();
}
}
public void HandleEvent(EventData data)
{
switch (data.eid)
{
case EventID.EVENT_1:
Event1 eve = data as Event1;
Debug.Log("receive event_1 msg!");
Debug.Log(string.Format("t1:{0},t2:{1},s1:{2}", eve.t1, eve.t2, eve.s1));
break;
case EventID.EVENT_2:
Debug.Log("receive event_2 msg!");
break;
}
}
void OnDestroy()
{
EventManager.Remove(this);
}
}

首先要继承EventObserver接口,然后在Start方法中进行注册,OnDestroy方法中进行注销。然后实现HandleEvent方法对消息进行处理。


把EventTest放到任意物体上并运行场景:

Unity简单事件系统管理之美_耦合度

当分别点击2个按钮时我们可以在控制台看到相应的输出:

Unity简单事件系统管理之美_事件系统_02