码迷,mamicode.com
首页 > 编程语言 > 详细

【Unity】线程安全的消息传输机制,仿照Cocos实现

时间:2015-01-11 13:35:31      阅读:284      评论:0      收藏:0      [点我收藏+]

标签:

近期用到了网络通信的方法,虽然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("我要睡觉");
}

最后当然输出“睡觉”咯


【Unity】线程安全的消息传输机制,仿照Cocos实现

标签:

原文地址:http://blog.csdn.net/nxshow/article/details/42610089

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!