Unity事件的高级监听与广播系统

        在大型的项目中,一般需要大量的事件来实现我们的功能,如果代码之间的耦合度高,相应的扩展性就会变得差一些。要改变一些要改变的代码时就要去找相应的引用,这会非常麻烦。降低代码的耦合度,可以大大提高项目的扩展性,给我们带来了方便。

基本思路是:每一个事件码对应一种事件,通过广播事件码,来触发相应的事件。

首先我们需要建立三个脚本来分别存放和处理不同方法和逻辑

1.创建一个单例模式的基类:BaseManager.cs

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

/// <summary>
/// 泛型基类:用于创建单例模式
/// </summary>
/// <typeparam name="T">类型</typeparam>
public class BaseManager <T> where T : new() {
    private static T _Instance;
	
    public static T GetInstance()
    {
        if (_Instance==null)
        {
           _Instance= new T();
        }
        return _Instance;
    }
}

 2.创建一个存放事件码的类(不需要继承MonoBehaviour):EventType.cs

public enum EventType
{
    
}

需要触发什么事件,就把事件码写在里面。

3.创建一个用来封装我们所使用到的所有委托: CallBack.cs

public delegate void CallBack();
public delegate void CallBack<X>(X arg);
public delegate void CallBack<X, Y>(X arg1,Y arg2);
public delegate void CallBack<X, Y, Z>(X arg1, Y arg2,Z arg3);
public delegate void CallBack<X, Y, Z, W>(X arg1, Y arg2, Z arg3,W arg4);
public delegate void CallBack<X, Y, Z, W, T>(X arg1, Y arg2, Z arg3, W arg,T arg5);

 这里主要使用C#的泛型委托,这个代码还可以扩展更多的参数,只要你需要多少个参数就可以写多少个,一般5个参数就可以了。

4.创建一个用于处理不同事件类型的监听,移除监听,广播:EventCenter.cs

主要思路:1.通过C#的Dictionary存放事件码和事件的委托

                  2.添加事件:判断字典是否有该事件码,没有添加;

                                       判断当前委托类型与添加的事件码的类型是否一致

                                       最后订阅该事件

                  3.移除事件: 先判断事件码是否存在

                                     取消订阅

                                     最后判断事件码是否为空,是null则移除事件码。

                 4.广播事件:若事件委托不为null ,广播事件。

using System;
using System.Collections.Generic;

public class EventCenter : BaseManager<EventCenter>
{
    public Dictionary<EventEnum, Delegate> m_EventTable = new Dictionary<EventEnum, Delegate>();

    /// <summary>
    /// 添加事件
    /// </summary>
    /// <param name="eventEnum">事件码</param>
    /// <param name="callBack">事件委托</param>
    public void AddListener(EventEnum eventEnum, CallBack callBack)
    {
        if (!m_EventTable.ContainsKey(eventEnum))
        {
            m_EventTable.Add(eventEnum, null);
        }
        Delegate d = m_EventTable[eventEnum];
        if (d != null && d.GetType() != callBack.GetType())
        {
            throw new Exception(string.Format("尝试事件为{0}添加不同类型委托,当前委托类型为{1},要添加的委托类型为{2}", eventEnum, d.GetType(), callBack.GetType()));
        }
        m_EventTable[eventEnum] = (CallBack)m_EventTable[eventEnum] + callBack;
    }

    /// <summary>
    /// one parameter
    /// </summary>
    /// <typeparam name="X">参数1</typeparam>
    /// <param name="eventEnum">事件码</param>
    /// <param name="callBack">事件委托</param>
    public void AddListener<X>(EventEnum eventEnum, CallBack<X> callBack)
    {
        if (!m_EventTable.ContainsKey(eventEnum))
        {
            m_EventTable.Add(eventEnum, null);
        }
        Delegate d = m_EventTable[eventEnum];
        if (d != null && d.GetType() != callBack.GetType())
        {
            throw new Exception(string.Format("尝试事件为{0}添加不同类型委托,当前委托类型为{1},要添加的委托类型为{2}", eventEnum, d.GetType(), callBack.GetType()));
        }
        m_EventTable[eventEnum] = (CallBack<X>)m_EventTable[eventEnum] + callBack;
    }
    /// <summary>
    /// two parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void AddListener<X,Y>(EventEnum eventEnum, CallBack<X,Y> callBack)
    {
        if (!m_EventTable.ContainsKey(eventEnum))
        {
            m_EventTable.Add(eventEnum, null);
        }
        Delegate d = m_EventTable[eventEnum];
        if (d != null && d.GetType() != callBack.GetType())
        {
            throw new Exception(string.Format("尝试事件为{0}添加不同类型委托,当前委托类型为{1},要添加的委托类型为{2}", eventEnum, d.GetType(), callBack.GetType()));
        }
        m_EventTable[eventEnum] = (CallBack<X,Y>)m_EventTable[eventEnum] + callBack;
    }

    /// <summary>
    /// three parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void AddListener<X, Y, Z>(EventEnum eventEnum, CallBack<X, Y, Z> callBack)
    {
        if (!m_EventTable.ContainsKey(eventEnum))
        {
            m_EventTable.Add(eventEnum, null);
        }
        Delegate d = m_EventTable[eventEnum];
        if (d != null && d.GetType() != callBack.GetType())
        {
            throw new Exception(string.Format("尝试事件为{0}添加不同类型委托,当前委托类型为{1},要添加的委托类型为{2}", eventEnum, d.GetType(), callBack.GetType()));
        }
        m_EventTable[eventEnum] = (CallBack<X, Y, Z>)m_EventTable[eventEnum] + callBack;
    }

    /// <summary>
    /// four parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <typeparam name="W"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void AddListener<X, Y, Z, W>(EventEnum eventEnum, CallBack<X, Y, Z, W> callBack)
    {
        if (!m_EventTable.ContainsKey(eventEnum))
        {
            m_EventTable.Add(eventEnum, null);
        }
        Delegate d = m_EventTable[eventEnum];
        if (d != null && d.GetType() != callBack.GetType())
        {
            throw new Exception(string.Format("尝试事件为{0}添加不同类型委托,当前委托类型为{1},要添加的委托类型为{2}", eventEnum, d.GetType(), callBack.GetType()));
        }
        m_EventTable[eventEnum] = (CallBack<X, Y, Z, W>)m_EventTable[eventEnum] + callBack;
    }

    /// <summary>
    /// five parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <typeparam name="W"></typeparam>
    /// <typeparam name="T"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void AddListener<X, Y, Z, W, T>(EventEnum eventEnum, CallBack<X, Y, Z, W, T> callBack)
    {
        if (!m_EventTable.ContainsKey(eventEnum))
        {
            m_EventTable.Add(eventEnum, null);
        }
        Delegate d = m_EventTable[eventEnum];
        if (d != null && d.GetType() != callBack.GetType())
        {
            throw new Exception(string.Format("尝试事件为{0}添加不同类型委托,当前委托类型为{1},要添加的委托类型为{2}", eventEnum, d.GetType(), callBack.GetType()));
        }
        m_EventTable[eventEnum] = (CallBack<X, Y, Z, W, T>)m_EventTable[eventEnum] + callBack;
    }

    /// <summary>
    /// 移除事件
    /// </summary>
    /// <param name="eventEnum">事件码</param>
    /// <param name="callBack">事件委托</param>
    public void RemoveListener(EventEnum eventEnum, CallBack callBack)
    {
        if (m_EventTable.ContainsKey(eventEnum))
        {
            Delegate d = m_EventTable[eventEnum];
            if (d == null)
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托类型", eventEnum));
            }
            else if (d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托,当前委托为{1},要移除的事件为{2}", eventEnum, d.GetType(), callBack.GetType()));
            }
        }
        else
        {
            throw new Exception(string.Format("移除事件错误:没有事件码{0}", eventEnum));
        }
        m_EventTable[eventEnum] = (CallBack)m_EventTable[eventEnum] - callBack;
        if (m_EventTable[eventEnum] == null)
        {
            m_EventTable.Remove(eventEnum);
        }
    }

    /// <summary>
    /// one parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void RemoveListener<X>(EventEnum eventEnum, CallBack<X> callBack)
    {
        if (m_EventTable.ContainsKey(eventEnum))
        {
            Delegate d = m_EventTable[eventEnum];
            if (d == null)
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托类型", eventEnum));
            }
            else if (d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托,当前委托为{1},要移除的事件为{2}", eventEnum, d.GetType(), callBack.GetType()));
            }
        }
        else
        {
            throw new Exception(string.Format("移除事件错误:没有事件码{0}", eventEnum));
        }
        m_EventTable[eventEnum] = (CallBack<X>)m_EventTable[eventEnum] - callBack;
        if (m_EventTable[eventEnum] == null)
        {
            m_EventTable.Remove(eventEnum);
        }
    }
    /// <summary>
    /// two parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void RemoveListener<X,Y>(EventEnum eventEnum, CallBack<X,Y> callBack)
    {
        if (m_EventTable.ContainsKey(eventEnum))
        {
            Delegate d = m_EventTable[eventEnum];
            if (d == null)
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托类型", eventEnum));
            }
            else if (d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托,当前委托为{1},要移除的事件为{2}", eventEnum, d.GetType(), callBack.GetType()));
            }
        }
        else
        {
            throw new Exception(string.Format("移除事件错误:没有事件码{0}", eventEnum));
        }
        m_EventTable[eventEnum] = (CallBack<X,Y>)m_EventTable[eventEnum] - callBack;
        if (m_EventTable[eventEnum] == null)
        {
            m_EventTable.Remove(eventEnum);
        }
    }

    /// <summary>
    ///  three parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void RemoveListener<X, Y, Z>(EventEnum eventEnum, CallBack<X, Y, Z> callBack)
    {
        if (m_EventTable.ContainsKey(eventEnum))
        {
            Delegate d = m_EventTable[eventEnum];
            if (d == null)
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托类型", eventEnum));
            }
            else if (d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托,当前委托为{1},要移除的事件为{2}", eventEnum, d.GetType(), callBack.GetType()));
            }
        }
        else
        {
            throw new Exception(string.Format("移除事件错误:没有事件码{0}", eventEnum));
        }
        m_EventTable[eventEnum] = (CallBack<X, Y, Z>)m_EventTable[eventEnum] - callBack;
        if (m_EventTable[eventEnum] == null)
        {
            m_EventTable.Remove(eventEnum);
        }
    }

    /// <summary>
    /// four parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <typeparam name="W"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void RemoveListener<X, Y, Z, W>(EventEnum eventEnum, CallBack<X, Y, Z, W> callBack)
    {
        if (m_EventTable.ContainsKey(eventEnum))
        {
            Delegate d = m_EventTable[eventEnum];
            if (d == null)
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托类型", eventEnum));
            }
            else if (d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托,当前委托为{1},要移除的事件为{2}", eventEnum, d.GetType(), callBack.GetType()));
            }
        }
        else
        {
            throw new Exception(string.Format("移除事件错误:没有事件码{0}", eventEnum));
        }
        m_EventTable[eventEnum] = (CallBack<X, Y, Z, W>)m_EventTable[eventEnum] - callBack;
        if (m_EventTable[eventEnum] == null)
        {
            m_EventTable.Remove(eventEnum);
        }
    }

    /// <summary>
    /// five parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <typeparam name="W"></typeparam>
    /// <typeparam name="T"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="callBack"></param>
    public void RemoveListener<X, Y, Z, W, T>(EventEnum eventEnum, CallBack<X, Y, Z, W, T> callBack)
    {
        if (m_EventTable.ContainsKey(eventEnum))
        {
            Delegate d = m_EventTable[eventEnum];
            if (d == null)
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托类型", eventEnum));
            }
            else if (d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("移除事件错误:事件{0}没有对应的委托,当前委托为{1},要移除的事件为{2}", eventEnum, d.GetType(), callBack.GetType()));
            }
        }
        else
        {
            throw new Exception(string.Format("移除事件错误:没有事件码{0}", eventEnum));
        }
        m_EventTable[eventEnum] = (CallBack<X, Y, Z, W, T>)m_EventTable[eventEnum] - callBack;
        if (m_EventTable[eventEnum] == null)
        {
            m_EventTable.Remove(eventEnum);
        }
    }

    /// <summary>
    /// 广播事件
    /// </summary>
    /// <param name="eventEnum"></param>
    public void BraodCastEvent(EventEnum eventEnum)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d))
        {
            CallBack callBack = d as CallBack;
            if (callBack != null)
            {
                callBack();
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}有不同类型的委托", eventEnum));
            }
        }
    }

    /// <summary>
    /// one parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="arg"></param>
    public void BraodCastEvent<X>(EventEnum eventEnum, X arg)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d))
        {
            CallBack<X> callBack = d as CallBack<X>;
            if (callBack != null)
            {
                callBack(arg);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}有不同类型的委托", eventEnum));
            }
        }
    }

    /// <summary>
    /// two parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="arg1"></param>
    /// <param name="arg2"></param>
    public void BraodCastEvent<X, Y>(EventEnum eventEnum, X arg1, Y arg2)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d))
        {
            CallBack<X,Y> callBack = d as CallBack<X,Y>;
            if (callBack != null)
            {
                callBack(arg1,arg2);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}有不同类型的委托", eventEnum));
            }
        }
    }

    /// <summary>
    /// three parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="arg1"></param>
    /// <param name="arg2"></param>
    /// <param name="arg3"></param>
    public void BraodCastEvent<X, Y, Z>(EventEnum eventEnum, X arg1, Y arg2, Z arg3)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d))
        {
            CallBack<X, Y, Z> callBack = d as CallBack<X, Y, Z>;
            if (callBack != null)
            {
                callBack(arg1, arg2, arg3);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}有不同类型的委托", eventEnum));
            }
        }
    }

    /// <summary>
    /// four parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <typeparam name="W"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="arg1"></param>
    /// <param name="arg2"></param>
    /// <param name="arg3"></param>
    /// <param name="arg4"></param>
    public void BraodCastEvent<X, Y, Z, W>(EventEnum eventEnum, X arg1, Y arg2, Z arg3, W arg4)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d))
        {
            CallBack<X, Y, Z, W> callBack = d as CallBack<X, Y, Z, W>;
            if (callBack != null)
            {
                callBack(arg1, arg2, arg3, arg4);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}有不同类型的委托", eventEnum));
            }
        }
    }

    /// <summary>
    /// five parameter
    /// </summary>
    /// <typeparam name="X"></typeparam>
    /// <typeparam name="Y"></typeparam>
    /// <typeparam name="Z"></typeparam>
    /// <typeparam name="W"></typeparam>
    /// <typeparam name="T"></typeparam>
    /// <param name="eventEnum"></param>
    /// <param name="arg1"></param>
    /// <param name="arg2"></param>
    /// <param name="arg3"></param>
    /// <param name="arg4"></param>
    /// <param name="arg5"></param>
    public void BraodCastEvent<X, Y, Z, W, T>(EventEnum eventEnum, X arg1, Y arg2, Z arg3, W arg4, T arg5)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventEnum, out d))
        {
            CallBack<X, Y, Z, W, T> callBack = d as CallBack<X, Y, Z, W, T>;
            if (callBack != null)
            {
                callBack(arg1, arg2, arg3, arg4, arg5);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误:事件{0}有不同类型的委托", eventEnum));
            }
        }
    }
}



 我们来做个试验,使用没有参数的。给一个场景创建一个Cube,点击按钮时显示出来

 首先在EventType脚本中添加一个事件码:

public enum EventType
{
    Test,
}

 给Cube添加一个脚本Test

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

public class Test : MonoBehaviour {

	void Start () {
        this.gameObject.SetActive(false);
        EventCenter.GetInstance().AddListener(EventType.Test, Show);
	}

    void Show()
    {
        this.gameObject.SetActive(true);
    }

    private void OnDestroy()
    {
        EventCenter.GetInstance().RemoveListener(EventType.Test, Show);
    }
}

 

创建一个Canvas,在Canvas下创建一个Button,给Button组件添加一个脚本Play.cs

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

public class Player : MonoBehaviour {
    private Button button;

    private void Start()
    {
        button = GetComponent<Button>();
        button.onClick.AddListener(()=> { EventCenter.GetInstance().BraodCastEvent(EventType.Test); });
        
    }

}

点击按钮就可以看到效果了!!

接下来在进行一个测试:有参数的;在刚刚的Canvas下创建一个Text组件

修改一下上面的Test脚本

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

public class Test01 : MonoBehaviour {

    private Text text;
	void Start () {
        text = GameObject.Find("Text").GetComponent<Text>();
        this.gameObject.SetActive(false);
        EventCenter.GetInstance().AddListener<string,string>(EventType.Test, Show);
	}

    void Show(string str1,string str2)
    {
        this.gameObject.SetActive(true);
        text.text = str1 + str2;
    }

    private void OnDestroy()
    {
        EventCenter.GetInstance().RemoveListener<string ,string>(EventType.Test, Show);
    }
}

再次修改Play.cs脚本

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

public class Player : MonoBehaviour {
    private Button button;

    private void Start()
    {
        button = GetComponent<Button>();
        button.onClick.AddListener(()=> { EventCenter.GetInstance().BraodCastEvent<string,string>(EventType.Test,"你好:","Unity!!!!"); });
        
    }

}

点击按钮就可以看到效果了!!!

到此事件监听与广播系统就完成了!!!!

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值