【Unity3D】基于C#的事件机制的实现

对很早以前学习的到的内容做备忘。

利用delegate(C++的函数指针)的特性,可以实现游戏内的事件机制,即注册事件,注销事件,一个脚本注册事件后,在发生事件时,注册的脚本函数可以作相应处理,以及回调。

首先,一个Manager类,用于保存所有注册了对应事件的函数,并且将其挂在一个全局的GameObject上。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventManager : MonoBehaviour {

    /// <summary>
    /// 该集合以一个k/v的形式保存事件集合
    /// k为事件ID,v是对应事件的处理函数,注意,v可以是一个委托集合
    /// </summary>
    static private Dictionary<EventTypeDefine, Delegate> eventLst = new Dictionary<EventTypeDefine, Delegate>();
    delegate void VoidlVoidDelegate();
    delegate void VoidStringDelegate(string s);

    /// <summary>
    /// 注册一个事件对应的处理函数
    /// </summary>
    /// <param name="eventID"></param>
    /// <param name="eventHandler"></param>
    public static void RegisterEvent(EventTypeDefine eventID,Action eventHandler)
    {
        if (!OnRegisterEvent(eventID, eventHandler))
            return;
        //eventLst[eventID] += eventHandler;
        //无返回类型的delegate可以作为Action,实际上在.net中,action就是对无返回值的delegate的封装
        //因此在下面的代码中,保存delegate的lst也可以保存action
        eventLst[eventID] = (Action)eventLst[eventID] + eventHandler;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="eventID"></param>
    /// <param name="eventHandler"></param>
    public static void RegisterEvent<T>(EventTypeDefine eventID, Action<T> eventHandler)
    {
        if (!OnRegisterEvent(eventID, eventHandler))
            return;
        eventLst[eventID] = (Action<T>)eventLst[eventID] + eventHandler;
    }

    public static void UnRegisterEvent(EventTypeDefine eventID, Action eventHandler)
    {
        if (!eventLst.ContainsKey(eventID))
            return;

        eventLst[eventID] = (Action)eventLst[eventID] - eventHandler;
    }

    public static void UnRegisterEvent<T>(EventTypeDefine eventID, Action<T> eventHandler)
    {
        if (!eventLst.ContainsKey(eventID))
            return;

        eventLst[eventID] = (Action<T>)eventLst[eventID] - eventHandler;
    }

    /// <summary>
    /// 检查
    /// </summary>
    /// <param name="eventID"></param>
    /// <param name="eventHandler"></param>
    /// <returns></returns>
    static bool OnRegisterEvent(EventTypeDefine eventID, Delegate eventHandler)
    {
        if (!eventLst.ContainsKey(eventID))//如果没有对应的事件ID,先把事件添加进去
            eventLst.Add(eventID, null);

        Delegate d = eventLst[eventID];
        if (d != null && d.GetType() == eventHandler.GetType())//如果对应的时间已经有相应的处理函数,且两个handler相等,则代表该事件已经注册了这个处理函数,不用重复添加
            return false;

        return true;
    }

    public static void TriggerEvent(EventTypeDefine eventID)
    {
        Delegate d = null;
        if (!eventLst.TryGetValue(eventID, out d))
            return;
        if (d == null)
            return;

        Delegate[] callBacks = d.GetInvocationList();
        for (int i = 0; i < callBacks.Length; i++)
        {
            Action callBack = callBacks[i] as Action;
            if (callBack == null)
                continue;

            callBack();
        }
    }

    public static void TriggerEvent<T>(EventTypeDefine eventID,T arg1)
    {
        Delegate d = null;
        if (!eventLst.TryGetValue(eventID, out d))
            return;
        if (d == null)
            return;

        Delegate[] callBacks = d.GetInvocationList();
        for (int i = 0; i < callBacks.Length; i++)
        {
            Action<T> callBack = callBacks[i] as Action<T>;
            if (callBack == null)
                continue;

            callBack(arg1);
        }
    }


}

对于要注册并且处理捕获/处理该事件的脚本,可以这样做:

这里把他放到一个button上做例子

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventLogic : MonoBehaviour {

    void OnEnable()
    {
        EventManager.RegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);//要处理的事件,对应的处理函数
        EventManager.RegisterEvent(EventTypeDefine.LoginButton2Click, OnLoginButtonClick);
        EventManager.RegisterEvent<string>(EventTypeDefine.LoginButton2Click, OnLoginButtonClick_2);
    }

    void OnDisable()
    {
        EventManager.UnRegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);
        EventManager.UnRegisterEvent<string>(EventTypeDefine.LoginButton2Click, OnLoginButtonClick_2);
    }

    public void LoginClick()
    {
        //UGUI的点击处理,点击button后触发该事件,NGUI略有不同但大致一样
        EventManager.TriggerEvent(EventTypeDefine.LoginButtonClick);
        //EventManager.UnRegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);
    }

    public void LoginClick_2()
    {
        EventManager.TriggerEvent(EventTypeDefine.LoginButton2Click, "带参数的事件触发");
        //EventManager.UnRegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);
    }

    private void OnLoginButtonClick()
    {
        Debug.Log("click");
    }
    private void OnLoginButtonClick_2(string s)
    {
        Debug.Log("click,arg:" + s);
    }
}

 

附上表示事件类型的枚举:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum EventTypeDefine
{
    LoginButtonClick,
    LoginButton2Click,
}

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值