U3D观察者模式,实现1对多

xiaoxiao2021-02-27  152

观察者类

using UnityEngine; using System.Collections; using System.Collections.Generic; public class Notification { /// <summary> /// 通知发送者 /// </summary> public GameObject sender; /// <summary> /// 通知内容 /// 备注:在发送消息时需要装箱、解析消息时需要拆箱 /// </summary> public object param; /// <summary> /// 构造函数 /// </summary> /// <param name="param"></param> public Notification(object param,GameObject sender = null) { this.sender = sender; this.param = param; } /// <summary> /// 实现ToString方法 /// </summary> /// <returns></returns> public override string ToString() { return string.Format("sender={0},param={1}", this.sender, this.param); } } public class NotificationCenter { /// <summary> /// 通知中心单例 /// </summary> private static NotificationCenter instance = null; public delegate void OnNotification(Notification notific); public static NotificationCenter Get() { if (instance == null) { instance = new NotificationCenter(); return instance; } return instance; } //实现一对多的消息 private Dictionary<string, Dictionary<GameObject, OnNotification>> m_dicEvent = new Dictionary<string, Dictionary<GameObject, OnNotification>>(); public void ObjAddEventListener(string eventKey, GameObject obj,OnNotification eventListener) { if (!m_dicEvent.ContainsKey(eventKey)) { Dictionary<GameObject, OnNotification> dic = new Dictionary<GameObject, OnNotification>(); dic[obj] = eventListener; m_dicEvent[eventKey] = dic; } else { m_dicEvent[eventKey][obj] = eventListener; } } public void ObjRemoveEventListener(string eventKey,GameObject obj) { if (!m_dicEvent.ContainsKey(eventKey)) return; m_dicEvent[eventKey].Remove(obj); } public void ObjDispatchEvent(string eventKey, object param = null,GameObject sender = null) { if (!m_dicEvent.ContainsKey(eventKey)) return; List<GameObject> listRemoveKey = new List<GameObject>(); List<OnNotification> listNoti = new List<OnNotification>(); lock (m_dicEvent) { foreach (var it in m_dicEvent[eventKey]) { if (it.Key != null) { //it.Value(new Notification(param, sender)); listNoti.Add(it.Value); } else { listRemoveKey.Add(it.Key); } } //删除已经Destory的GameObject for (int i = 0; i < listRemoveKey.Count; i++) { m_dicEvent[eventKey].Remove(listRemoveKey[i]); } for ( int i = 0; i < listNoti.Count; i++) { listNoti[i](new Notification(param, sender)); } } } /// <summary> /// 是否存在指定事件的监听器 /// </summary> public bool HasEventListener(string eventKey) { return m_dicEvent.ContainsKey(eventKey); } }

使用:

订阅消息与取消订阅消息

void EventInit() { NotificationCenter.Get().ObjAddEventListener(KEventKey.m_evOpenInputTip, gameObject, OnEventOpenInputTip); } private void OnDestroy() { NotificationCenter.Get().ObjRemoveEventListener(KEventKey.m_evOpenInputTip, gameObject); } void OnEventOpenInputTip(Notification param) { }

发布消息

NotificationCenter.Get().ObjDispatchEvent(KEventKey.m_evDown, 1);

注意的地方1

lock (m_dicEvent) { foreach (var it in m_dicEvent[eventKey]) { if (it.Key != null) { //it.Value(new Notification(param, sender)); listNoti.Add(it.Value); } else { listRemoveKey.Add(it.Key); } } //删除已经Destory的GameObject for (int i = 0; i < listRemoveKey.Count; i++) { m_dicEvent[eventKey].Remove(listRemoveKey[i]); } for ( int i = 0; i < listNoti.Count; i++) { listNoti[i](new Notification(param, sender)); } }

发出消息时,1.根据GameObject是否存在,删除对应消息表中。 2。先保存一遍要处理的消息,因为有些委托是创建对象,如果对象初始化执行

public void Awake() { SetExamJianXiuDian(); for (int i = 0; i < m_listId.Count; i++) { m_dicId[m_listId[i]] = false; } NotificationCenter.Get().ObjAddEventListener(KEventKey.m_evExamJianXiuDian, gameObject, OnEvJianXiuDian); NotificationCenter.Get().ObjAddEventListener(KEventKey.m_evChallengeCommit, gameObject, OnEvCommit); NotificationCenter.Get().ObjAddEventListener(KEventKey.m_evChallengeNext, gameObject, OnEvNext); }

就会产生执行委托,边遍历字典边修改字典问题

注意的地方2

void OnEvNext(Notification noti) { if (gameObject.activeSelf == true) ChallengeMgr.m_instance.OnNextRet(GetScore()); }

当执行委托时,要判断下这个脚本的GameObject是否激活状态,再去执行委托,不然出现一些难以确定bug

转载请注明原文地址: https://www.6miu.com/read-14568.html

最新回复(0)