您好,欢迎来到Unity之家!   unity.jb51.net 
  • 首 页
  • 你问我答
  • 当前位置:首页 > 程序开发 > 开发经验 >
    基于Unity的多线程之间的事件派发
    时间:2015-02-06 10:08 来源:Unity之家 作者:unity.jb51.net 浏览:收藏 挑错 推荐 打印




    用unity做网游的同学应该不少,其中一个很蛋疼的问题就是主线程中尤其是UI部分很多实例都是不允许子线程修改的,

    那么我们就只有想办法把这些子线程里的数据缓存起来,让主线程自己拿着这些数据该干嘛干嘛去。


    直接贴源码:



    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using UnityEngine;
    using System.Threading;
    public class EventDispatcher
    {
        private static EventDispatcher sinstance;
        public static EventDispatcher Instance()
        {
            if (sinstance == null)
            {
                sinstance = new EventDispatcher();
            }
            return sinstance;
        }
    //  object m_objLock = new object();
    //  object m_objLock2 = new object();
        public delegate void EventCallback(EventBase eb);
        private Dictionary<string, List<EventCallback>> registedCallbacks = new Dictionary<string, List<EventCallback>>();
        private Dictionary<string, List<EventCallback>> registedCallbacksPending = new Dictionary<string, List<EventCallback>>();
        private List<EventBase> lPendingEvents = new List<EventBase>();
        public void RegistEventListener(string sEventName, EventCallback eventCallback)
        {
            lock (this)
            {
                if (!registedCallbacks.ContainsKey(sEventName))
                {
                    registedCallbacks.Add(sEventName, new List<EventCallback>());
                }
                if (isEnuming)
                {
                    if (!registedCallbacksPending.ContainsKey(sEventName))
                    {
                        registedCallbacksPending.Add(sEventName, new List<EventCallback>());
                    }
                    registedCallbacksPending[sEventName].Add(eventCallback);
                    return;
                }
                registedCallbacks[sEventName].Add(eventCallback);
            }
        }
        public void UnregistEventListener(string sEventName, EventCallback eventCallback)
        {
            lock (this)
            {
                if (!registedCallbacks.ContainsKey(sEventName))
                {
                    return;
                }
                if (isEnuming)
                {
                    Debug.Log("Cannot unregist event this moment!");
                    return;
                }
                registedCallbacks[sEventName].Remove(eventCallback);
            }
        }
        List<EventBase> lEvents = new List<EventBase>();
        public void DispatchEvent<T>(T eventInstance)
            where T:EventBase
        {
            lock (this)
            {
                if (!registedCallbacks.ContainsKey(eventInstance.sEventName))
                {
                    return;
                }
                if (isEnuming)
                {
                    lPendingEvents.Add(eventInstance);
                    Debug.Log("Cannot dispatch event this moment!");
                    return;
                }
                foreach (EventBase eb in lPendingEvents)
                {
                    lEvents.Add(eb);
                }
                lPendingEvents.Clear();
                lEvents.Add(eventInstance);
            }
        }
        public void DispatchEvent(string eventName, object eventValue)
        {
            lock (this)
            {
                if (!registedCallbacks.ContainsKey(eventName))
                {
                    return;
                }
                if (isEnuming)
                {
                    lPendingEvents.Add(new EventBase(eventName, eventValue));
                    Debug.Log("Cannot dispatch event this moment!");
                    return;
                }
                lEvents.Add(new EventBase(eventName, eventValue));
            }
        }
        private void testPendingEvents()
        {
            foreach (EventBase eb in lPendingEvents)
            {
                lEvents.Add(eb);
            }
            lPendingEvents.Clear();
        }
        public static bool isEnuming = false;
        public void OnTick()
        {
            lock (this)
            {
                if (lEvents.Count == 0)
                {
                    foreach (string sEventName in registedCallbacksPending.Keys)
                    {
                        foreach (EventCallback ec in registedCallbacksPending[sEventName])
                        {
                            RegistEventListener(sEventName, ec);
                        }
                    }
                    registedCallbacksPending.Clear();
                    testPendingEvents();
                    return;
                }
                isEnuming = true;
                foreach (EventBase eb in lEvents)
                {
                    for ( int i = 0;i<registedCallbacks[eb.sEventName].Count;i++)// EventCallback ecb in registedCallbacks[eb.sEventName])
                    {
                        EventCallback ecb = registedCallbacks[eb.sEventName];
                        if (ecb == null)
                        {
                            continue;
                        }
                        ecb(eb);
                    }
                }
                lEvents.Clear();
            }
            isEnuming = false;
        }
    }
    public class EventBase
    {
        public object eventValue;
        public string sEventName;
        public EventBase()
        {
            sEventName = this.GetType().FullName;
        }
        public EventBase(string eventName, object ev)
        {
            eventValue = ev;
            sEventName = eventName;
        }
    }
    public class ChatEvent : EventBase
    {
        public int iChannel;
        public string sContent;
        public string sName;
        public ChatEvent()
        {
        }
    }



    使用方法很简单,在随便哪个Monobehaviour脚本里的Update函数里调用EventDispatcher.Instance().OnTick();就可以了


    using UnityEngine;
    using System.Collections;
    public class EventTicker : MonoBehaviour
    {
        void Start()
        {
        }
        void Update()
        {
            EventDispatcher.Instance().OnTick();
        }
    }


    需要派发事件时:


    EventDispatcher.Instance().DispatchEvent("EventName", eventValue);



    eventValue可以是任何类型的数据。

    在需要的地方监听事件:


    EventDispatcher.Instance().RegistEventListener("EventName",EventCallback );


    其中EventCallback是一个参数为EventBase的函数:


    void EventCallback(EventBase eb)
    {
        Debug.Log("EventCallback:" + eb.eventValue.ToString());
    }




    进阶用法:

    细心的同学应该发现了,EventDispatcher类的最下面有个ChatEvent,


    public class ChatEvent : EventBase


    调用


    ChatEvent ce = new ChatEvent();
    EventDispatcher.Instance().DispatchEvent<ChatEvent>(ce);


    在监听函数里


    void chatCallBack(EventBase eb)
        {
            ChatEvent ce = eb as ChatEvent;
    }


    酱紫,就可以很方便取出自定义的事件中的多个参数了~



    (责任编辑:脚印)
    免责声明:Unity之家部分内容来源于互联网,如有侵权,请联系我们,本站将立即进行处理。