Unity C# 事件监听和广播

事件监听和广播

创建三个脚本

1. EventCenter   事件的处理中心

2. EvenType      存放事件码

3. CallBack      定义委托的类

添加监听的时候要先传递过来一个事件码,一个委托

实现一个简单功能,按钮点击显示所有Text文本和内容

一.EventCenter 脚本

1.脚本不需要继承MonoBehaviour,不需要绑定物体

   //定义一个字典 来存放事件码,注意参数类型不要少写一个t

private Dictionary<EventType, Delegate> m_EventTable = new Dictionary<EventType, Delegate>();

Dictionary字典

EventType事件码变量

Delegate:  委托 要加命名空间 using System; 委托首字母大写,具体用法还要深入研究

m_EventTable字典表名

if (!m_EventTable.ContainsKey(eventType))

       {

         //先给字典添加事件码,委托设置为空

         m_EventTable.Add(eventType, null);

    }

ContainsKey()字典的属性 确定字典中是否包含指定的键,返回Bool值

Add():         字典添加元素的方法

Remove():       字典删除指定元素 Key

GetType():      返回某个实例具体引用的数据类型.C#中任何对象都具有GetType()方法,x.GetType(),其中x为变量名

string.Format():  将多个对象格式化成一个字符串

    TryGetValue:     当在字典中不能确定是否存在该键时需要使用TryGetValue,以减少一次不必要的查找,同时避免了判断Key值是否存在而引发的给定关键字不在字典中。的错误。(TryGetValue是根据ID返回相应的数据,如果没有ID则返回默认值)

///事件的处理中心
///处理不同事件的参数的监听
///不同参数的移除监听
///广播
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


/// <summary>
/// 不需要继承MonoBehaviour
/// </summary>
public class EventCenter
{
    //定义一个字典 来存放事件码
    private static Dictionary<EventType, Delegate> m_EventTable = new Dictionary<EventType, Delegate>();


//*************************************************************************************************************************************
    /// <summary>
    /// 判断事件监听是不是有错误
    /// </summary>
    /// <param name="eventType">事件码</param>
    /// <param name="callBack">委托</param>
    /// 主要是为了精简代码
    private static void OnListenerAdding(EventType eventType, Delegate callBack)
    {
        //先判断事件码是否存在于事件表中
        //如果不存在
        if (!m_EventTable.ContainsKey(eventType))
        {
            //先给字典添加事件码,委托设置为空
            m_EventTable.Add(eventType, null);
        }

        //当前事件码和委托是否一致
        //如果不一致,是不能绑定在一起的
        //先把事件码传进去,接收值是 Delegate
        //这句代码是先把事件码拿出来
        Delegate d = m_EventTable[eventType];
        //d为空或d 的参数如果和callBack参数不一样
        if (d != null && d.GetType() != callBack.GetType())
        {
            //抛出异常
            throw new Exception(string.Format("尝试为事件{0}添加不同事件的委托,当前事件所对应的委托是{1},要添加的委托类型{2}", eventType, d.GetType(), callBack.GetType()));
        }
    }

    /// <summary>
    /// 移除监听时做的判断,主要为精简代码
    /// </summary>
    /// <param name="eventType">事件码</param>
    /// <param name="callBack">委托</param>
    private static void OnListenerRemoving(EventType eventType, Delegate callBack)
    {
        //判断是否包含指定键
        if (m_EventTable.ContainsKey(eventType))
        {
            //先把事件码拿出来
            Delegate d = m_EventTable[eventType];
            if (d == null)
            {
                throw new Exception(string.Format("移除监听错误:事件{0}没有对应的委托", eventType));
            }
            else if (d.GetType() != callBack.GetType())//判断移除的委托类型是否和d的一致
            {
                throw new Exception(string.Format("移除监听错误,尝试为事件{}移除不同类型的委托,当前委托类型为{1},要移除的委托类型为{2}", eventType, d.GetType(), callBack.GetType()));
            }
        }
        else  //不存在事件码的情况
        {
            throw new Exception(string.Format("移除监听错误;没有事件码", eventType));
        }
    }

    /// <summary>
    /// 移除监听后的判断,主要为精简代码
    /// </summary>
    /// <param name="eventType"></param>
    private static void OnListenerRemoved(EventType eventType)
    {
        //判断当前的事件码所对应的事件是否为空
        //如果为空,事件码就没用了,就将事件码移除
        if (m_EventTable[eventType] == null)
        {
            //移除事件码
            m_EventTable.Remove(eventType);
        }
    }


//*********************************************************************************************************************************
    /// <summary>
    /// 添加监听 静态 无参
    /// </summary>
    /// <param name="eventType">事件码</param>
    /// <param name="callBack">委托</param>
    public static void AddListener(EventType eventType, CallBack callBack)
    {
        //调用事件监听是不是有错误方法
        OnListenerAdding(eventType, callBack);

        //已经存在的委托进行关联,相当于链式关系,再重新赋值
        //两个类型不一致,要强转换
        //委托对象可使用 "+" 运算符进行合并。
        //一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。
        //使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。
        //下面的程序演示了委托的多播
        m_EventTable[eventType] = (CallBack)m_EventTable[eventType] + callBack;
    }

    /// <summary>
    /// 添加监听 静态 一个参数
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="eventType"></param>
    /// <param name="callBack"></param>
    /// 因为有一个参数,方法后要加一个泛型“<T>”,大写的T来代表
    /// CallBack 也是一个泛型,方法是有参数的,所以CallBack也是有参数的
    /// 除此之外其它与无参方法基本一致
    /// 泛函数 T 可以指定为任意的类型,多参数也是
    public static void AddListener<T>(EventType eventType, CallBack<T> callBack)
    {
        //调用事件监听是不是有错误方法
        OnListenerAdding(eventType, callBack);

        //这里是有参方法需要更改的地方
        //强制转换类型要加一个泛型 "<T>"
        m_EventTable[eventType] = (CallBack<T>)m_EventTable[eventType] + callBack;
    }

    /// <summary>
    /// 添加监听 静态 两个参数
    /// </summary>
    public static void AddListener<T,X>(EventType eventType, CallBack<T,X> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T,X>)m_EventTable[eventType] + callBack;
    }

    /// <summary>
    /// 添加监听 静态 三个参数
    /// </summary>
    public static void AddListener<T, X, Y>(EventType eventType, CallBack<T, X, Y> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y>)m_EventTable[eventType] + callBack;
    }

    /// <summary>
    /// 添加监听 静态 四个参数
    /// </summary>
    public static void AddListener<T, X, Y, Z>(EventType eventType, CallBack<T, X, Y, Z> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y, Z>)m_EventTable[eventType] + callBack;
    }

    /// <summary>
    /// 添加监听 静态 五个参数
    /// </summary>
    public static void AddListener<T, X, Y, Z, W>(EventType eventType, CallBack<T, X, Y, Z, W> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y, Z, W>)m_EventTable[eventType] + callBack;
    }


    //*******************************************************************************************************************************
    /// <summary>
    /// 移除监听 静态 无参
    /// </summary>
    /// <param name="eventType">事件码</param>
    /// <param name="callBack">委托</param>
    public static void RemoveListener(EventType eventType, CallBack callBack)
    {
        //移除监听前的判断
        OnListenerRemoving(eventType, callBack);

        //这句话是主要的
        //事件码对应的委托-callBack 然后再重新赋值,强转型首字母要大写
        //移除监听
        m_EventTable[eventType] = (CallBack)m_EventTable[eventType] - callBack;

        //移除监听后的判断
        OnListenerRemoved(eventType);
    }

    /// <summary>
    /// 移除监听 静态 一个参数
    /// </summary>
    /// <param name="eventType">事件码</param>
    /// <param name="callBack">委托</param>
    public static void RemoveListener<T>(EventType eventType, CallBack<T> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        //这里是有参方法需要更改的地方
        //强制转换类型要加一个泛型 "<T>"
        m_EventTable[eventType] = (CallBack<T>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }

    /// <summary>
    /// 移除监听 静态 两个参数
    /// </summary>
    public static void RemoveListener<T,X>(EventType eventType, CallBack<T,X> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T,X>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }

    /// <summary>
    /// 移除监听 静态 三个参数
    /// </summary>
    public static void RemoveListener<T, X, Y>(EventType eventType, CallBack<T, X, Y> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }


    /// <summary>
    /// 移除监听 静态 四个参数
    /// </summary>
    public static void RemoveListener<T, X, Y, Z>(EventType eventType, CallBack<T, X, Y, Z> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y, Z>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }

    /// <summary>
    /// 移除监听 静态 五个参数
    /// </summary>
    public static void RemoveListener<T, X, Y, Z, W>(EventType eventType, CallBack<T, X, Y, Z,W> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (CallBack<T, X, Y, Z, W>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }

    //******************************************************************************************************************************
    /// <summary>
    /// 广播监听 静态 无参
    /// </summary>
    /// <param name="eventType">事件码</param>
    /// 把事件码所对应的委托从m_EventTable 字典表中取出来,然后调用这个委托
    public static void Broadcast(EventType eventType)
    {
        Delegate d;
        //如果拿到这个值成功了,对这个委托进行一个广播
        if (m_EventTable.TryGetValue(eventType, out d))
        {
            //把d强转型CallBack类型
            CallBack callBack = d as CallBack;
            if (callBack != null)
            {
                callBack();
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}对应的委托具有不同类型", eventType));
            }
        }
    }


    /// <summary> 
    /// 广播监听 静态 一个参
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="eventType"></param>
    /// <param name="arg"></param>
    /// 以为有参数,所以在方法后面加一个参数 T arg
    public static void Broadcast<T>(EventType eventType, T arg)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventType, out d))
        {
            //带有一个参数的委托
            CallBack<T> callBack = d as CallBack<T>;
            if (callBack != null)
            {
                //把参数传过去
                callBack(arg);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}对应的委托具有不同类型", eventType));
            }
        }
    }

    /// <summary>
    /// 广播 静态 两个参数
    /// </summary>
    public static void Broadcast<T,X>(EventType eventType, T arg1,X arg2)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventType, out d))
        {
            CallBack<T,X> callBack = d as CallBack<T,X>;
            if (callBack != null)
            {
                callBack(arg1,arg2);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}对应的委托具有不同类型", eventType));
            }
        }
    }

    /// <summary>
    /// 广播 静态 三个参数
    /// </summary>
    public static void Broadcast<T, X, Y>(EventType eventType, T arg1, X arg2, Y arg3)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventType, out d))
        {
            CallBack<T, X, Y> callBack = d as CallBack<T, X, Y>;
            if (callBack != null)
            {
                callBack(arg1, arg2, arg3);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}对应的委托具有不同类型", eventType));
            }
        }
    }

    /// <summary>
    /// 广播 静态 四个参数
    /// </summary>
    public static void Broadcast<T, X, Y, Z>(EventType eventType, T arg1, X arg2, Y arg3, Z arg4)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventType, out d))
        {
            CallBack<T, X, Y, Z> callBack = d as CallBack<T, X, Y, Z>;
            if (callBack != null)
            {
                callBack(arg1, arg2, arg3, arg4);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}对应的委托具有不同类型", eventType));
            }
        }
    }

    /// <summary>
    /// 广播 静态 五个参数
    /// </summary>
    public static void Broadcast<T, X, Y, Z, W>(EventType eventType, T arg1, X arg2, Y arg3, Z arg4, W arg5)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventType, out d))
        {
            CallBack<T, X, Y, Z, W> callBack = d as CallBack<T, X, Y, Z, W>;
            if (callBack != null)
            {
                callBack(arg1, arg2, arg3, arg4, arg5);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}对应的委托具有不同类型", eventType));
            }
        }
    }
}

二.EventType 脚本

1.存放事件码

2.枚举类型

3.后续有什么需要,可以自定义添加

4.不需要任何命名空间,Clss类,继承,挂载物体

///存放事件码
///枚举类型
///后续有什么需要,可以自定义添加
public enum EventType
{
    ShowText,
}

enum :枚举类型

ShowText:自己定义的变量

枚举是一组命名整型常量。枚举类型是使用 enum 关键字声明的。

变量要用 逗号 “ ,”隔开,最后一个变量不用逗号

C# 枚举是值类型。换句话说,枚举包含自己的值,且不能继承或传递继承。

1、通过 Enum.GetNames(),和 Enum.GetValues() 进行名称和值的数组获取,从而实现遍历

2、之间使用 Enum 枚举值,默认 0 ,每个值增加 1 的特点,使用 for 的 i++ 使用遍历

三.CallBack 脚本

1.不需要任何命名空间,Clss类,继承,挂载物体

2.封装里了系统所使用到的委托

3.定义委托的类

4.定义多少参数都是可以的

5.定义了多少委托,EventCenter添加多少委托,过多添加会报错

CallBack脚本是种什么写法?

菜鸟教程:委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。

例如,假设有一个委托:

public delegate int MyDelegate (string s);

上面的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。

声明委托的语法如下:

delegate <return type> <delegate-name> <parameter list>

委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。

使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。下面的程序演示了委托的多播

///封装里了系统所使用到的委托
///定义委托的类
///定义多少参数都是可以的
///定义了多少委托,EventCenter添加多少委托,过多添加会报错

/// <summary>
/// 无参委托
/// </summary>
public delegate void CallBack();


/// <summary>
/// 有参委托,一个参数,需要指定一个泛型,( 泛型类型 变量名 )
/// </summary>
/// <typeparam name="T">泛型类型</typeparam>
/// <param name="arg">变量名</param>
public delegate void CallBack<T>(T arg);


/// <summary>
/// 多个参数
/// </summary>
/// <typeparam name="T">泛型类型</typeparam>
/// <typeparam name="X">泛型类型</typeparam>
/// <param name="arg1">变量名</param>
/// <param name="arg2">变量名</param>
/// 一般只用到5个,如果还需要可以往后加
public delegate void CallBack<T, X>(T arg1, X arg2);
public delegate void CallBack<T, X, Y>(T arg1, X arg2, Y arg3);
public delegate void CallBack<T, X, Y, Z>(T arg1, X arg2, Y arg3, Z arg4);
public delegate void CallBack<T, X, Y, Z, W>(T arg1, X arg2, Y arg3, Z arg4, W arg5);

delegate: 委托声明

注册委托时的方法需要注意的点:

 1.返回值类型要一致,下面我的返回值类型都是void,所以我注册的方法也必须是void返回值类型

 2.参数的个数以及参数类型要保持一致

四.添加监听,移除监听,广播方法的使用

1.添加监听

1.方法参数为(事件码 方法)

        2.参数里面的方法并不需要加参数

        3.泛型类型要和参数的类型一致,不一致会报错

        4.方法是自己写的方法

       

//单个参数

EventCenter.AddListener<string >(EventType.ShowText, Show);

脚本名     .方法名    <泛函数类型>(枚举.枚举变量   ,方法);

//多个参数

EventCenter.AddListener<string, string, float, int, bool>(EventType.ShowText, Show2);

2.移除监听

//单个参数

EventCenter.RemoveListener<string>(EventType.ShowText, Show);

脚本名   .方法名      <泛函数类型>(枚举.枚举变量   ,方法);

EventCenter.RemoveListener<string ,string, float, int, bool >(EventType.ShowText, Show);

3.广播

//调用广播的方法

//有参数时,要在广播后面加相应类型的参数

//一个参数(string)

 EventCenter.Broadcast(EventType.ShowText,"你被监听了");

//四个参数(string,string float,int ,bool)

EventCenter.Broadcast(EventType.ShowText, "你被监听了", "对 是你", 12.02f, 36, true);

4.自己随便写的方法

//获取参数,并开启Txet对象,并赋值文字,一个参数

//将脚本绑定在Text文本物体上

public void Show(string str)

    {

        gameObject.SetActive(true);

        GetComponent<Text>().text = str;

}

广播后的结果:text文本显示:你被监听了

//四个参数

private void Show2(string str,string str1,float a,int b,bool c)

    {

        gameObject.SetActive(true);

        if (c)

        {

          GetComponent<Text>().text = str+str1+a+b+c;

        }

}

广播后的结果:text文本显示:你被监听了对是你12.02f36true

这些脚本的方法调用,与脚本绑定还要在研究实践

以上脚本内容均采用Siki学院教学视频,制作成笔记供自己学习

猜你喜欢

转载自blog.csdn.net/podaosanshiliu/article/details/125658019