Unity 3D 消息事件系统 NotificationCenter、CEventDispatcher事件分发机制

时间:2021-05-23 23:42:51

版本:unity 5.4.1  语言:C#

 

实战核心技术这本书来到了第三章,这里给了一个消息事件系统,这是几乎每一个游戏系统都会用到的一个常用技术,非常好用,但如果你add之后忘记remove的话。。。相信每个使用过它的人都经历过这样的痛苦。

 

闲话不多说,书中类的名字是CEventDispatcher,而我会按照我的习惯来实现一遍,就叫做NotificationCenter,对,cocos中的名称。

 

在看书之前,我自己也写过一个,是依靠NGUI中的EventDelegate写的,然后调用传递链也是自己写来调用,看起来还是比较复杂的,而书上的实现就非常简洁了。

 

下面是代码:

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

// 消息的类型
public enum NotifyType
{
PLAYER_ON_HURT,
BLOCK_PLACE,
}

// 消息事件类,使用中传递的信息
public class NotifyEvent
{
protected Dictionary<string, string> arguments; //参数
protected NotifyType type; //事件类型
protected System.Object sender; //发送者

// bean函数
public NotifyType Type
{
get { return type; }
set { type = value; }
}

public Dictionary<string, string> Params
{
get { return arguments; }
set { arguments = value; }
}

public System.Object Sender
{
get { return sender; }
set { sender = value; }
}

// 常用函数
public override string ToString()
{
return type + " [ " + ((sender == null) ? "null" : sender.ToString()) + " ] ";
}

public NotifyEvent Clone()
{
return new NotifyEvent(type, arguments, sender);
}

// 构造函数
public NotifyEvent(NotifyType type, System.Object sender)
{
Type = type;
Sender = sender;
if (arguments == null)
{
arguments = new Dictionary<string, string>();
}
}

public NotifyEvent(NotifyType type, Dictionary<string, string> args, System.Object sender)
{
Type = type;
arguments = args;
Sender = sender;
if (arguments == null)
{
arguments = new Dictionary<string, string>();
}
}
}

// 消息监听者,这是一个delegate,也就是一个函数,当事件触发时,对应注册的delegate就会触发
public delegate void EventListenerDelegate(NotifyEvent evt);

// 消息中心
public class NotifacitionCenter
{
// 单例
private static NotifacitionCenter instance;
private NotifacitionCenter() { }
public static NotifacitionCenter getInstance()
{
if (instance == null)
{
instance = new NotifacitionCenter();
}
return instance;
}

// 成员变量
Dictionary<NotifyType, EventListenerDelegate> notifications = new Dictionary<NotifyType, EventListenerDelegate>() ; // 所有的消息


// 注册监视
public void registerObserver(NotifyType type, EventListenerDelegate listener)
{
if (listener == null)
{
Debug.LogError("registerObserver: listener不能为空");
return;
}

// 将新来的监听者加入调用链,这样只要调用Combine返回的监听者就会调用所有的监听者
Debug.Log("NotifacitionCenter: 添加监视" + type);

EventListenerDelegate myListener = null;
notifications.TryGetValue(type, out myListener);
notifications[type] = (EventListenerDelegate)Delegate.Combine(myListener, listener);
}

// 移除监视
public void removeObserver(NotifyType type, EventListenerDelegate listener)
{
if (listener == null)
{
Debug.LogError("removeObserver: listener不能为空");
return;
}

// 与添加的思路相同,只是这里是移除操作
Debug.Log("NotifacitionCenter: 移除监视" + type);
notifications[type] = (EventListenerDelegate)Delegate.Remove(notifications[type], listener);
}

public void removeAllObservers()
{
notifications.Clear();
}

// 消息触发
public void postNotification(NotifyEvent evt)
{
EventListenerDelegate listenerDelegate;
if(notifications.TryGetValue(evt.Type, out listenerDelegate))
{
try
{
// 执行调用所有的监听者
listenerDelegate(evt);
}
catch(System.Exception e)
{
throw new Exception(string.Concat(new string[] { "Error dispatching event", evt.Type.ToString(), ": ", e.Message, " ", e.StackTrace }), e);
}
}
}

}

以上就是代码的全部了,实际上就是Delegate的使用,这样一些小项目用这个类往上一套,就能很轻松的实现很多逻辑了。

 

不过最后还是要提醒一下,添加了监听,一定要有删除监听,他们是成对出现的。