近期用到了网络通信的方法,虽然unity可以用协程来实现异步操作,不过坑爹的队友不会用,他用的是传统的开线程的方法,这样就会出现线程安全的问题,然后现有的消息通信机制无法满足需求了,就得改了。还好我机智的看过Cocos2dx中消息机制的实现原理,顺手改了一下,下面贴源码:(源码后有解释)
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; /** * 消息派发类 */ namespace Assets.TGUI.UIScript { public class CDispatcher { //单例 public static readonly CDispatcher Instance = new CDispatcher(); //消息委托函数 public delegate void noticeDelegate(object[] data); /// <summary> /// 消息Key /// </summary> public struct Key { public string name; public object target; public Key(string _name, object _target) { name = _name; target = _target; } } //存储消息列表 private Dictionary<Key, noticeDelegate> m_noticeDict; private List<KeyValuePair<Key, object[]>> m_noticeRequest; private List<KeyValuePair<Key, object[]>> m_tempRequest; private CDispatcher() { m_noticeDict = new Dictionary<Key, noticeDelegate>(); m_noticeRequest = new List<KeyValuePair<Key, object[]>>(); m_tempRequest = new List<KeyValuePair<Key, object[]>>(); } /// <summary> /// 循环遍历 执行消息请求 /// </summary> public IEnumerator Dispatcher() { Debug.Log("MSG: Start Dispatcher"); do { if (m_tempRequest.Count != 0) { lock (m_tempRequest) { foreach (var item in m_tempRequest) { m_noticeRequest.Add(new KeyValuePair<Key, object[]>(item.Key, item.Value)); } m_tempRequest.Clear(); } foreach (var item in m_noticeRequest) { if (m_noticeDict.ContainsKey(item.Key)) { m_noticeDict[item.Key](item.Value); } } m_noticeRequest.Clear(); } yield return new WaitForFixedUpdate(); } while (true); } /** * 发送消息 * @param notifyName 消息类型 * @param data 携带参数 */ public void sendNotification(string noticeName, object[] data = null) { sendNotification(noticeName, null, data); } /// <summary> /// 发送消息 /// </summary> /// <param name="noticeName"></param> /// <param name="target"></param> /// <param name="data"></param> public void sendNotification(string noticeName, object target, object[] data) { m_tempRequest.Add(new KeyValuePair<Key, object[]>(new Key(noticeName, target), data)); } /// <summary> /// 发送消息 附带的数据是发送者本身的对象 /// </summary> /// <param name="noticeName"></param> /// <param name="target"></param> /// <param name="source"></param> public void sendNotification(string noticeName, object target, object source) { sendNotification(noticeName, target, new object[] { source }); } /// <summary> /// 获取到源类型变量 /// (与sendNotification(string noticeName, /// object target, object source)对应) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data"></param> /// <returns></returns> public T GetSourceObject<T>(object[] data) { return (T)data[0]; } public void addObserver(string noticeName, noticeDelegate notice) { addObserver(noticeName, null, notice); } public void addObserver(string noticeName, object target, noticeDelegate notice) { Key key = new Key(noticeName, target); if (!m_noticeDict.ContainsKey(key)) { m_noticeDict.Add(key, notice); } } public void RemoveObserver(string noticeName) { RemoveObserver(noticeName, null); } public void RemoveObserver(string noticeName, object target) { Key key = new Key(noticeName, target); if (!m_noticeDict.ContainsKey(key)) { m_noticeDict.Remove(key); } } } }
方法稍微有点略多,但是值得关注的方法就是下面几个
IEnumerator Dispatcher() public void sendNotification(...) public void addObserver(...) public void RemoveObserver(...)
首先来说第一个,第一个是消息循环遍历的方法,需要在游戏主对象中的start方法中使用协程开启消息循环遍历,写法如下:
//开启消息循环 StartCoroutine(CDispatcher.Instance.Dispatcher());
然后和Cocos2dx一样,添加观察者
CDispatcher.Instance.addObserver("消息名字", [目标对象], 方法);
然后发送消息
CDispatcher.Instance.sendNotification("消息名字",[目标对象],[附加数据]);
下面是一个完整的使用例子:
protected void Start() { //开启消息循环 StartCoroutine(CDispatcher.Instance.Dispatcher()); CDispatcher.Instance.addObserver("我要睡觉", x => Debug.Log("睡觉")); CDispatcher.Instance.sendNotification("我要睡觉"); }
最后当然输出“睡觉”咯
时间: 2024-10-16 01:53:21