【Unity】事件中心

事件中心模块
本篇文章只是用来记录学习的笔记。
单例模式基类
知识点:
Dictionary,委托,观察者模式
委托和事件详解
作用:
降低程序耦合性,减小程序复杂度

在这里插入图片描述
按照这张图来创建4个脚本以及对象


在这里插入图片描述


Monster

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

public class Monster : MonoBehaviour
{
    void Start()
    {
        Dead();
    }

    /// <summary>
    /// 死亡方法
    /// </summary>
    void Dead()
    {
        Debug.Log("怪物死亡");

        //玩家得奖励
        GameObject.Find("Player").GetComponent<Player>().MonsterDeadDo();
        //任务记录
        GameObject.Find("Task").GetComponent<Task>().TaskWaitMonsterDeadDo();
        //其它
        GameObject.Find("Other").GetComponent<Other>().OtherWaitMonsterDeadDo();
        //等等
        
    }
}

Player

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

public class Player : MonoBehaviour
{
    /// <summary>
    /// 怪物死亡时要做些什么
    /// </summary>
    /// <param name="info"></param>
    public void MonsterDeadDo()
    {
        Debug.Log("玩家得奖励" );
    }
}

Task

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

public class Task : MonoBehaviour
{
    public void TaskWaitMonsterDeadDo()
    {
        Debug.Log("任务,记录");
    }
}

Other

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

public class Other : MonoBehaviour
{
    /// <summary>
    /// 怪物死的时候要做的事
    /// </summary>
    /// <param name="info"></param>
    public void OtherWaitMonsterDeadDo()
    {
        Debug.Log("其它 各个对象要做的事情");
    }
}

将脚本挂载到对应的对象上
运行结果如下:
在这里插入图片描述
怪物死亡后,触发另外三个脚本。如果还需要其他很多事件都在monster类中写的话耦合性会很高。
所以引入事件中心的概念,由事件中心来处理收发事件。


在这里插入图片描述
在这里插入图片描述


事件中心代码EventCenter

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

/// <summary>
/// 事件中心 单例模式对象
/// 1.Dictionary
/// 2.委托
/// 3.观察者设计模式
/// </summary>
public class EventCenter :BaseManger<EventCenter> 
{
    //key对应的是事件的名字
    //value对应的是监听这个事件对应的委托函数们
    private Dictionary<string, UnityAction> eventDic = new Dictionary<string, UnityAction>();
    
    /// <summary>
    ///添加事件监听 
    /// </summary>
    /// <param name="name">事件的名字</param>
    /// <param name="action">准备用来处理事件的委托函数</param>
    public void AddEventListener(string name, UnityAction action)
    {
        //判断字典里有没有对应这个事件,有就执行,没有就加进去。
        if (eventDic.ContainsKey(name))
        {
            eventDic[name] += action;
        }
        else
        {
            eventDic.Add(name, action);
        }
    }
    /// <summary>
    /// 事件触发
    /// </summary>
    /// <param name="name">哪一个名字的事件触发了</param>
    public void EventTrigger(string name)
    {
        if (eventDic.ContainsKey(name))
        {
            // eventDic[name]();
            eventDic[name].Invoke();
        }
    }
}


Monster

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

public class Monster : MonoBehaviour
{
    void Start()
    {
        Dead();
    }

    /// <summary>
    /// 死亡方法
    /// </summary>
    void Dead()
    {
        Debug.Log("怪物死亡");

        //触发事件
        EventCenter.instance.EventTrigger("MonsterDead"); 
    }
}


Other

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

public class Other : MonoBehaviour
{

     void Start()
    {
        EventCenter.instance.AddEventListener("MonsterDead", OtherWaitMonsterDeadDo); 
    }


    /// <summary>
    /// 怪物死的时候要做的事
    /// </summary>
    /// <param name="info"></param>
    public void OtherWaitMonsterDeadDo()
    {
        Debug.Log("其它 各个对象要做的事情");
    }
}


Player

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

public class Player : MonoBehaviour
{
    void Start()
    {
        EventCenter.instance.AddEventListener("MonsterDead", MonsterDeadDo);
    }

    /// <summary>
    /// 怪物死亡时要做些什么
    /// </summary>
    /// <param name="info"></param>
    public void MonsterDeadDo()
    {
        Debug.Log("玩家得奖励" );
    }
}


Task

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

public class Task : MonoBehaviour
{
    void Start()
    {
        EventCenter.instance.AddEventListener("MonsterDead", TaskWaitMonsterDeadDo);
    }

    public void TaskWaitMonsterDeadDo()
    {
        Debug.Log("任务,记录");
    }
}


运行如下图:
在这里插入图片描述
与全都在monster类中写触发一致,这种方法大大降低了耦合度,思路清晰。


在某个事件被添加后,需要移除。当某个事件一直被引用的时候有可能会造成内存泄漏或者报错,所以还需要移除事件。

    /// <summary>
    /// 移除对应的实践监听
    /// </summary>
    /// <param name="name">事件的名字</param>
    /// <param name="action">对应之前添加的委托函数</param>
    public void RemoveEventListener(string name,UnityAction action)
    {
        if (eventDic.ContainsKey(name))
        {
            eventDic[name] -= action;
        }
    }


当对象销毁时回执行Ondestory生命周期函数,移除监听事件。

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

public class Task : MonoBehaviour
{
    void Start()
    {
        EventCenter.instance.AddEventListener("MonsterDead", TaskWaitMonsterDeadDo);
    }

    public void TaskWaitMonsterDeadDo()
    {
        Debug.Log("任务,记录");
    }

    void OnDestroy()
    {
        EventCenter.instance.RemoveEventListener("MonsterDead", TaskWaitMonsterDeadDo); 
    }
}


某些时候忘记添加移除事件的函数,或者场景切换时出现问题时,监听事件没有移除干净,这时候就需要清空事件中心。

    /// <summary>
    /// 清空事件中心
    /// 主要用在场景切换时
    /// </summary>
    public void Clear()
    {
        eventDic.Clear();
    }

现在还有一个问题是,当有多种怪物死亡时(多种触发条件)无法具体判断是哪种怪物从而导致事件的混乱,为了解决这个问题,使用泛型委托。所有对象都是继承于object,用object可以代替很多类型变量。虽然会有拆箱装箱的消耗,但是这样就可以通用。
EventCenter

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

/// <summary>
/// 事件中心 单例模式对象
/// 1.Dictionary
/// 2.委托
/// 3.观察者设计模式
/// </summary>
public class EventCenter :BaseManger<EventCenter> 
{
    //key对应的是事件的名字
    //value对应的是监听这个事件对应的委托函数们
    private Dictionary<string, UnityAction<object>> eventDic = new Dictionary<string, UnityAction<object>>();
    
    /// <summary>
    ///添加事件监听 
    /// </summary>
    /// <param name="name">事件的名字</param>
    /// <param name="action">准备用来处理事件的委托函数</param>
    public void AddEventListener(string name, UnityAction<object> action)
    {
        //判断字典里有没有对应这个事件,有就执行,没有就加进去。
        if (eventDic.ContainsKey(name))
        {
            eventDic[name] += action;
        }
        else
        {
            eventDic.Add(name, action);
        }
    }

    /// <summary>
    /// 移除对应的实践监听
    /// </summary>
    /// <param name="name">事件的名字</param>
    /// <param name="action">对应之前添加的委托函数</param>
    public void RemoveEventListener(string name,UnityAction<object> action)
    {
        if (eventDic.ContainsKey(name))
        {
            eventDic[name] -= action;
        }
    }

    /// <summary>
    /// 事件触发
    /// </summary>
    /// <param name="name">哪一个名字的事件触发了</param>
    public void EventTrigger(string name,object info)
    {
        if (eventDic.ContainsKey(name))
        {
            // eventDic[name]();
            eventDic[name].Invoke(info);
        }
    }

    /// <summary>
    /// 清空事件中心
    /// 主要用在场景切换时
    /// </summary>
    public void Clear()
    {
        eventDic.Clear();
    }
}


Monster

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

public class Monster : MonoBehaviour
{
    public string Tite= "经验到手";
    void Start()
    {
        Dead();
    }

    /// <summary>
    /// 死亡方法
    /// </summary>
    void Dead()
    {
        Debug.Log("怪物死亡");

        //触发事件
        EventCenter.instance.EventTrigger("MonsterDead",this);
        
    }
}


Player

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

public class Player : MonoBehaviour
{
    void Start()
    {
        EventCenter.instance.AddEventListener("MonsterDead", MonsterDeadDo);
    }

    /// <summary>
    /// 怪物死亡时要做些什么
    /// </summary>
    /// <param name="info"></param>
    public void MonsterDeadDo(object info)
    {
        Debug.Log("玩家得奖励"+(info as Monster).Tite );
    }

    void OnDestroy()
    {
        EventCenter.instance.RemoveEventListener("MonsterDead", MonsterDeadDo);
    }
}


运行结果如下:
在这里插入图片描述


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值