zoukankan      html  css  js  c++  java
  • Unity3D 全局逻辑事件/消息派发 实现

    1.先看下怎么使用的

    1)脚本中注册逻辑事件

            void Start () 
            {
                m_pGUICanvasObj = GameObject.Find("Canvas");
                if(m_pGUICanvasObj != null)
                {
                    m_pGUICanvasObj.SetActive(false);
                }
           //为当前MonoBehaviour脚本注册对于MENU_VISIBLE_CHANGED事件的监听器
                EventDispatchModule.GetSingletonInstance().RegisterEventHandler(LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED,this);
            }

    2)脚本销毁时移除

            void OnDestroy() 
            {
           //当脚本销毁时,移除监听器 EventDispatchModule.GetSingletonInstance().RemoveEventHandler(LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED,
    this); }

    3)发送全局逻辑事件

            public void Btn_BackToGame()
            {
                m_bShowMenu = false;
                //这里全局逻辑事件传递的参数可以是任意类型的,以引用传递
                EventDispatchModule.SendWrap<bool>(LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED,ref m_bShowMenu);
            }

    4)响应逻辑事件(这里暂时比较挫,没有以回调的形式体现,后面再改)

            public bool HandMessage(LOGIC_EVENT_ID iLogicEventID, ref object obj)
            {
                switch(iLogicEventID)
                {
                case LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED:
                {
                    OnMenuVisibleChanged();
                    return true;//return true 表示其它监听器可以继续处理该事件,false表示吞噬事件
                }
                default:
                    break;
                }
                return true;
            }

    2.实现细节

    1)所有需要监听消息的类,实现EventListener接口

    public interface EventListener
    {
        //return true-continue.
        //return false-end.
        bool HandMessage(LOGIC_EVENT_ID iLogicEventID,ref object obj);
    }

    2)附上上文的XCraft.CtrlScript脚本代码

    using UnityEngine;
    using System.Collections;
    using XCraft.HighLevelManager;
    using XCraft.Module;
    namespace XCraft.CtrlScript
    {
        public class GUICtrl : MonoBehaviour ,EventListener{
            private bool m_bShowMenu = false;
            private GameObject m_pGUICanvasObj = null;
    
            public bool HandMessage(LOGIC_EVENT_ID iLogicEventID, ref object obj)
            {
                switch(iLogicEventID)
                {
                case LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED:
                {
                    OnMenuVisibleChanged();
                    return true;
                }
                default:
                    break;
                }
                return true;
            }
    
            void OnDestroy() 
            {
                EventDispatchModule.GetSingletonInstance().RemoveEventHandler(LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED,this);
            }
    
            // Use this for initialization
            void Start () 
            {
                m_pGUICanvasObj = GameObject.Find("Canvas");
                if(m_pGUICanvasObj != null)
                {
                    m_pGUICanvasObj.SetActive(false);
                }
    
                EventDispatchModule.GetSingletonInstance().RegisterEventHandler(LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED,this);
            }
            
            // Update is called once per frame
            void Update () 
            {
                ApplicationManager.GetSingletonInstance().UpdateInstances(Time.deltaTime);
    
                if(Input.GetKeyDown(KeyCode.Escape))
                {
                    m_bShowMenu = !m_bShowMenu;
    
                    EventDispatchModule.SendWrap<bool>(LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED,ref m_bShowMenu);
                }
            }
    
            private void OnMenuVisibleChanged()
            {
                if(m_bShowMenu == true)
                {
                    Debug.Log("Show Menu");
                    if(m_pGUICanvasObj != null)
                    {
                        m_pGUICanvasObj.SetActive(true);
                    }
    
                }
                else
                {
                    Debug.Log("Close Menu");
                    if(m_pGUICanvasObj != null)
                    {
                        m_pGUICanvasObj.SetActive(false);
                    }
                }
            }
    
            public void Btn_BackToGame()
            {
                m_bShowMenu = false;
    
                EventDispatchModule.SendWrap<bool>(LOGIC_EVENT_ID.MENU_VISIBLE_CHANGED,ref m_bShowMenu);
            }
    
            public void Btn_SaveAndReturn()
            {
                Application.LoadLevel("TitleScene");
            }
    
        }
    }
        
    View Code

    3)消息派发中心EventDispatchModule

    Dictionary保存关于逻辑事件ID事件监听者列表的 键值对,监听者列表用HashSet

      1 using UnityEngine;
      2 using System.Collections.Generic;
      3 using UnityEngine.Assertions;
      4 public interface EventListener
      5 {
      6     //return true-continue.
      7     //return false-end.
      8     bool HandMessage(LOGIC_EVENT_ID iLogicEventID,ref object obj);
      9 }
     10 namespace XCraft.Module
     11 {
     12     public class EventDispatchModule : Singleton<EventDispatchModule>,ModuleInterface
     13     {
     14         private Dictionary< LOGIC_EVENT_ID,HashSet<EventListener> > m_mapEventListners = null;
     15         public EventDispatchModule()
     16         {
     17             m_mapEventListners = new Dictionary< LOGIC_EVENT_ID, HashSet<EventListener> >();
     18         }
     19         
     20         ~EventDispatchModule(){}
     21         
     22         public void Init()
     23         {
     24             
     25         }
     26         
     27         public void Start()
     28         {
     29             
     30         }
     31         
     32         public void Update(float deltaSecond)
     33         {
     34             
     35         }
     36 
     37         //In order to improve the efficiency, use generic and reference   --HuangXufeng
     38         static public void SendWrap<T>(LOGIC_EVENT_ID iLogicEventID,ref T args)
     39         {
     40             EventArgs<T> evtArgs = new EventArgs<T>(iLogicEventID,ref args);
     41             object evtObj = (object)evtArgs;
     42             EventDispatchModule.GetSingletonInstance().SendMessage(iLogicEventID,ref evtObj);
     43         } 
     44 
     45         public void SendMessage(LOGIC_EVENT_ID iLogicEventID,ref object objArgs) 
     46         {
     47             HashSet<EventListener> listenerSet = null;
     48             if(m_mapEventListners.TryGetValue(iLogicEventID,out listenerSet))
     49             {
     50                 if(listenerSet == null)
     51                 {
     52                     Assert.IsTrue (false);
     53                     return;
     54                 }
     55                 
     56                 foreach(EventListener evtListener in listenerSet)
     57                 {
     58                     if(false == evtListener.HandMessage(iLogicEventID,ref objArgs))
     59                     {
     60                         break;
     61                     }
     62                 }
     63             }
     64             else
     65             {
     66                 //iLogicEventID do not Register Listener
     67                 Assert.IsTrue(false);
     68             }
     69         }
     70 
     71         public void RegisterEventHandler(LOGIC_EVENT_ID iLogicEventID,EventListener IEventListenerInstance)
     72         {
     73             HashSet<EventListener> listenerSet = null;
     74             if(m_mapEventListners.TryGetValue(iLogicEventID,out listenerSet))
     75             {
     76                 if(listenerSet == null)
     77                 {
     78                     Assert.IsTrue(false);
     79                     return;
     80                 }
     81 
     82                 Assert.IsTrue(listenerSet.Add(IEventListenerInstance));
     83             }
     84             //if listener list == null ,create one
     85             else
     86             {
     87                 HashSet<EventListener> newHashSet = new HashSet<EventListener>(){IEventListenerInstance};
     88                 m_mapEventListners.Add(iLogicEventID,newHashSet);
     89             }
     90         }
     91 
     92         public void RemoveEventHandler(LOGIC_EVENT_ID iLogicEventID,EventListener IEventListenerInstance)
     93         {
     94             HashSet<EventListener> listenerSet = null;
     95             if(m_mapEventListners.TryGetValue(iLogicEventID,out listenerSet))
     96             {
     97                 if(listenerSet == null)
     98                 {
     99                     Assert.IsTrue(false);
    100                     return;
    101                 }
    102                 
    103                 Assert.IsTrue(listenerSet.Remove(IEventListenerInstance));
    104             }
    105             else
    106             {
    107                 Assert.IsTrue(false);
    108             }
    109         }
    110     }
    111 }
    View Code

    3.小结

    为了支持逻辑事件参数可以是基础类型、类类型,用了C#的泛型,感觉相比C++仍缺失很多灵活度(如果是C++中可以直接将任意类型转Void*,然后在HandleMessage处再强转回去,灵活许多,而且C#引用 ref关键字 调用和函数声明处都得写- -!!)

    上文举例时用了继承MonoBehaviour的GUICtrl作为示范,当然不继承MonoBehaviour也是可以的,只是需要注意在监听者生命周期结束后,RemoveEvent就行。

  • 相关阅读:
    element-ui的table表格控件表头与内容列不对齐问题
    uniapp 调用手机相机拍照实现图片上传
    配置Git忽略文件
    【转载】Java的几种常见排序算法
    httpclient封装
    idea 启动springboot项目时报错:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource
    shell脚本监控网站,异常则进行邮件报警
    nginx配置图片跨域访问
    Nginx基于多端口、多域名配置
    docker部署Nginx项目dockerfile
  • 原文地址:https://www.cnblogs.com/kyokuhuang/p/5392127.html
Copyright © 2011-2022 走看看