Unity简单事件系统管理

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

直接上代码:
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:
public class EventTest : MonoBehaviour ,EventObserver{
	public string uname = "aaa";
	public string password = "bbb";
	// Use this for initialization
	void Start () {
        EventManager.Register(this,EventID.EVENT_1,EventID.EVENT_2);
	}
	// Update is called once per frame
	void Update () {
	}
	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放到任意物体上并运行场景:

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

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引