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

 

直接上代码:

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简单事件系统管理之美_Unity教程

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

Unity简单事件系统管理之美_Unity_02