GameFramework框架 (四) Evnet组件 EventComponent

前言

在第三篇的流程代码中,多次出现了 GameEntry.Event.XXX的影子, 所以,今天就学习Event组件。

事件

事件 (Event) – 游戏逻辑监听、抛出事件的机制。Game Framework 中的很多模块在完成操作后都会抛出内置事件,监听这些事件将大大解除游戏逻辑之间的耦合。用户也可以定义自己的游戏逻辑事件。

大白话说事件:

举个栗子, 有几只小猫和一个饲养员

每个小猫都有几个方法:  预约(Subscribe)     取消预约(UnSubscribe)    DoSomething (Handler)   DoOtherSomthing(Handler)

饲养员有一个小本本(集合), 可以在小本本里面添加信息(Add)或者擦除信息(Remove), 饲养员可以发送通知 Fire 

------------------------------------------------

小猫A比较贪吃,跟饲养员预约说, 12点了及时通知我,我要吃小鱼干, 饲养员把小猫A的预约信息添加进了小本本

小猫B比较贪玩,跟饲养员说预约说,12点了及时通知我,我要出去逛,饲养员把小猫B的预约信息添加进了小本本

小猫C喜欢交友,跟饲养员预约说,12点了及时通知我,我要出去找朋友,饲养员把小猫C的预约信息添加进了小本本

其他小猫都没有和饲养员预约任何事情;

过了一段时间,

小猫D找小猫B说, 我们一起去滑冰吧,小猫B痛快的同意了,跟饲养员说,我取消12点的预约了,饲养员擦除了(Remove)小猫B的预约

时间过得很快,一转眼就到12点了

饲养员翻开小本本,看到小本本上还记录着小猫A和小猫C的预约信息, 逐一通知(Fire)小猫A和小猫C去干各自的事情

 观察者模式:设计模式——观察者模式_做哈白日梦的博客-CSDN博客_设计模式观察者模式

---------------------------------------------------------------------------------

下面的脚本是ProcedureMenu.cs中的代码

  //ProcedureMenu.cs
protected override void OnEnter(ProcedureOwner procedureOwner)
        {
            base.OnEnter(procedureOwner);
            //本篇讨论这行代码
            GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OnOpenUIFormSuccess);

            m_StartGame = false;
            //下一篇文章讨论这行代码
            GameEntry.UI.OpenUIForm(UIFormId.MenuForm, this);
        }

        //事件处理函数
        private void OnOpenUIFormSuccess(object sender, GameEventArgs e)
        {
            OpenUIFormSuccessEventArgs ne = (OpenUIFormSuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            m_MenuForm = (MenuForm)ne.UIForm.Logic;
        }

注意看代码中的注释

追踪Game.Event.Subscribe函数,定位到 EventComponent.cs

  public void Subscribe(int id, EventHandler handler)
        {
            //这里是添加到集合的操作
            m_EventManager.Subscribe(id, handler);
        }

继续追到 EventManager.cs

  public void Subscribe(int id, EventHandler handler)
        {
            m_EventPool.Subscribe(id, handler);
        }

继续追到 EventPool.cs, 最后把 id,handle 添加到 m_EventHandle字典中 

 m_EventHandlers.Add(id, handler);

  public void Subscribe(int id, EventHandler handler)
        {
            if (handler == null)
            {
                throw new GameFrameworkException("Event handler is invalid.");
            }

            if (!m_EventHandlers.Contains(id))
            {
                //添加到集合
                m_EventHandlers.Add(id, handler);
            }
            else if ((m_EventPoolMode & EventPoolMode.AllowMultiHandler) != EventPoolMode.AllowMultiHandler)
            {
                throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow multi handler.", id));
            }
            else if ((m_EventPoolMode & EventPoolMode.AllowDuplicateHandler) != EventPoolMode.AllowDuplicateHandler && Check(id, handler))
            {
                throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow duplicate handler.", id));
            }
            else
            {
                m_EventHandlers.Add(id, handler);
            }
        }

注册的时候把事件id和handler加入到了m_EventHandlers中

事件注册了, 那什么时候触发事件执行呢?

查找所有引用:发现在UIComponent组件中,Fire了事件

GameFramework框架 (四) Evnet组件 EventComponent_第1张图片

//UIComponent.cs
 protected override void Awake()
        {
            base.Awake();

            m_UIManager = GameFrameworkEntry.GetModule();
            if (m_UIManager == null)
            {
                Log.Fatal("UI manager is invalid.");
                return;
            }

            if (m_EnableOpenUIFormSuccessEvent)
            {
                m_UIManager.OpenUIFormSuccess += OnOpenUIFormSuccess;
            }

            m_UIManager.OpenUIFormFailure += OnOpenUIFormFailure;

            if (m_EnableOpenUIFormUpdateEvent)
            {
                m_UIManager.OpenUIFormUpdate += OnOpenUIFormUpdate;
            }

            if (m_EnableOpenUIFormDependencyAssetEvent)
            {
                m_UIManager.OpenUIFormDependencyAsset += OnOpenUIFormDependencyAsset;
            }

            if (m_EnableCloseUIFormCompleteEvent)
            {
                m_UIManager.CloseUIFormComplete += OnCloseUIFormComplete;
            }
        }

 private void OnOpenUIFormSuccess(object sender, GameFramework.UI.OpenUIFormSuccessEventArgs e)
        {
            //触发事件
            m_EventComponent.Fire(this, OpenUIFormSuccessEventArgs.Create(e));
        }

继续追:

 //EventComponent.cs
public void Fire(object sender, GameEventArgs e)
        {
            m_EventManager.Fire(sender, e);
        }


//EventManager.cs
 public void Fire(object sender, GameEventArgs e)
        {
            m_EventPool.Fire(sender, e);
        }


//EventPool.cs
 public void Fire(object sender, T e)
        {
            if (e == null)
            {
                throw new GameFrameworkException("Event is invalid.");
            }

            Event eventNode = Event.Create(sender, e);
            lock (m_Events)
            {
                //这里如队列
                m_Events.Enqueue(eventNode);  
            }
        }

 public void Update(float elapseSeconds, float realElapseSeconds)
        {
            lock (m_Events)
            {
                while (m_Events.Count > 0)
                {
                    Event eventNode = m_Events.Dequeue();
                    HandleEvent(eventNode.Sender, eventNode.EventArgs);
                    ReferencePool.Release(eventNode);
                }
            }
        }



 private void HandleEvent(object sender, T e)
        {
            bool noHandlerException = false;
            GameFrameworkLinkedListRange> range = default(GameFrameworkLinkedListRange>);
            //从集合中取出handler执行
            if (m_EventHandlers.TryGetValue(e.Id, out range))
            {
                LinkedListNode> current = range.First;
                while (current != null && current != range.Terminal)
                {
                    m_CachedNodes[e] = current.Next != range.Terminal ? current.Next : null;
                    current.Value(sender, e);
                    current = m_CachedNodes[e];
                }

                m_CachedNodes.Remove(e);
            }
            else if (m_DefaultHandler != null)
            {
                m_DefaultHandler(sender, e);
            }
            else if ((m_EventPoolMode & EventPoolMode.AllowNoHandler) == 0)
            {
                noHandlerException = true;
            }

            ReferencePool.Release(e);

            if (noHandlerException)
            {
                throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow no handler.", e.Id));
            }
        }

触发的时候从m_EventHandlers中取出之前添加的handler,调用执行

 private void OnOpenUIFormSuccess(object sender, GameEventArgs e)
        {
            OpenUIFormSuccessEventArgs ne = (OpenUIFormSuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            m_MenuForm = (MenuForm)ne.UIForm.Logic;
        }

在GF框架中的事件使用和OnOpenUIFormSuccess基本都差不多。

自定义事件:注意看代码中的注释

举个栗子:假设我们现在有n多个关卡,玩家可以在任意关卡之间切换,每一个关卡我们可以定义一个流程,比如 ProcedureLevelA, ProcedureLevelB, ProcedureLevelC...

可以给关卡的切换定义一个事件:

//必须继承自 GameEventArgs
public class ChangeProcedureEventArgs : GameEventArgs
    {
        public static readonly int EventId = typeof(ChangeProcedureEventArgs).GetHashCode();

        //定义我们自己的参数
        //这是我们要跳转到下一个关卡的参数
        public SceneId sceneId { get; private set; }

        public override int Id
        {
            get
            {
                return EventId;
            }
        }

        public override void Clear()
        {
            sceneId = SceneId.None;
        }

        //创建事件,给自定义参数赋值
        public static ChangeProcedureEventArgs Create(SceneId id)
        {
            ChangeProcedureEventArgs e = ReferencePool.Acquire();
            e.sceneId = id;
            return e;
        }

在流程的OnEnter中注册事件,OnLeave中取消事件

  public class ProcedureStart : ProcedureBase
    {
    
        private ProcedureOwner m_ProdureOwner;  
        public override bool UseNativeDialog
        {
            get
            {
                return false;
            }
        }

       
        protected override void OnEnter(ProcedureOwner procedureOwner)
        {
            base.OnEnter(procedureOwner);
            m_ProdureOwner = procedureOwner;
            Log.Info("进入ProcedureStart================");
            //注册事件
            GameEntry.Event.Subscribe(ChangeProcedureEventArgs.EventId, RspChangeScene);        
            GameEntry.UI.OpenUIForm(UIFormId.SplashForm, this);
        }


        protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
        {
            base.OnLeave(procedureOwner, isShutdown);
            //取消事件
            GameEntry.Event.Unsubscribe(ChangeProcedureEventArgs.EventId, RspChangeScene);
           
        }


        protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);

          
        }

      

      //事件处理函数
        protected void RspChangeScene(object sender,GameEventArgs e)
        {
            if (m_ProdureOwner == null)
            {
                return;
            }

            ChangeProcedureEventArgs ne = e as ChangeProcedureEventArgs;
            if (ne.sceneId == SceneId.None)
            {
                return;
            }
            //从事件参数中获取关卡ID,调用切换关卡的流程
            m_ProdureOwner.SetData(Constant.ProcedureData.NextSceneId, (int)ne.sceneId);
            ChangeState(m_ProdureOwner);

        }

    }

无论在任何地方,只要调用下面这行代码,传入要跳转的关卡名,就可以跳转关卡了

 GameEntry.Event.Fire(this, ChangeProcedureEventArgs.Create(SceneId.MainMenu));

你可能感兴趣的:(GameFramework,GF框架,GameFramework框架)