事件中心
观察者模式
大概理解就是一种一对多的关系
当这个特定对象的状态发生改变的时候
所有依赖于这个对象的对象们都会收到改变的信息
然后做出对应的反应
事件中心是什么
我们知道框架里可能有很多个不同的管理器
但是这些管理器肯定没办法做到完全独立
彼此之间还是会有一些逻辑处理和数据交换
同理 游戏里有很多不同的对象 对象之间也涉及到交流
假如互相引用的话代码看起来就不太好看
所以我们就想到了交给第三方来处理
也就是事件中心
作为发起人 我告诉事件中心什么事情发生了
作为委托人 我告诉事件中心当某件事发生时我会去做什么
然后事件中心就开始监听 监听到发起人说某件事发生了
便会告诉委托人你现在该做啥了
这就是事件中心的工作原理
PS:这里的坑在于监听对象是否有限制的问题
事件中心的代码实现
我们依然选择了字典作为我们的存放对象
string作为key 也就是事件名
而事件作为我们的值
关于这里事件的封装其实比较没有那么复杂
其实就是包装了一层接口 然后做里氏替换
关键是为什么要这样做呢?
事件中心这个类是单例对吧 他是唯一的 那么给事件中心这个类加上泛型就会很奇怪
因为它只会初始化一次 你只能传一次类型
例如说你想在类里直接用UnityAction
所以这里我们在外面小小封装了一下
不用object很明显 就是为了避免装箱拆箱
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public interface I_EventGeneric
{
}
public class EventGeneric<T> : I_EventGeneric
{
public UnityAction<T> actions;
public EventGeneric(UnityAction<T> action)
{
actions += action;
}
}
public class EventGeneric : I_EventGeneric
{
public UnityAction actions;
public EventGeneric(UnityAction action)
{
actions += action;
}
}
/// <summary>
/// 事件中心 单例
/// 事件触发要晚于事件监听
/// </summary>
public class EventCenter : BaseManager<EventCenter>
{
//存放事件的容器 Key是事件名 value是监听事件对应的委托函数们
private Dictionary<string, I\_EventGeneric> eventDic = new Dictionary<string, I\_EventGeneric>();
/// <summary>
/// 添加事件监听
/// </summary>
/// <param name="name">事件名</param>
/// <param name="action">处理事件的委托函数</param>
public void AddEventListener<T>(string name, UnityAction<T> action)
{
//有没有对应的事件监听
if(eventDic.ContainsKey(name))
{
//有就直接添加
(eventDic\[name\] as EventGeneric<T>).actions += action;
}
else
{
//没有就要创建
eventDic.Add(name, new EventGeneric<T>(action));
}
}
/// <summary>
/// 移除事件监听
/// </summary>
/// <param name="name">移除的事件名</param>
/// <param name="action">事件添加的委托函数</param>
public void RemoveEventListener<T>(string name, UnityAction<T> action)
{
if (eventDic.ContainsKey(name))
{
(eventDic\[name\] as EventGeneric<T>).actions -= action;
}
//销毁时调用 OnDestroy()
}
/// <summary>
/// 事件触发
/// </summary>
/// <param name="name">触发的事件名</param>
public void EventTrigger<T>(string name, T info)
{
if (eventDic.ContainsKey(name) && (eventDic\[name\] as EventGeneric<T>).actions != null)
{
(eventDic\[name\] as EventGeneric<T>).actions.Invoke(info);
}
}
/// <summary>
/// 清空事件中心 防止场景切换时溢出
/// </summary>
public void Clear()
{
eventDic.Clear();
}
}事件中心的使用
假设现在我们有一个怪物类 作为事件的发起者 死亡的时候进行触发
有一个任务类和一个玩家类 分别委托了怪物死亡的时候要做的事情
具体实现如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Task : MonoBehaviour
{
void Awake()
{
EventCenter.GetInstance().AddEventListener<Monster>("MonsterDie", TaskDone);
}
void OnDestroy()
{
EventCenter.GetInstance().RemoveEventListener<Monster>("MonsterDie", TaskDone);
}
public void TaskDone(Monster info)
{
Debug.Log("任务完成");
}
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Monster : MonoBehaviour
{
void Start()
{
Die();
}
public void Die()
{
Debug.Log("怪物死亡");
//触发事件
EventCenter.GetInstance().EventTrigger("MonsterDie", this);
}
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Awake()
{
EventCenter.GetInstance().AddEventListener<Monster>("MonsterDie", GetBonus);
}
void OnDestroy()
{
EventCenter.GetInstance().RemoveEventListener<Monster>("MonsterDie", GetBonus);
}
public void GetBonus(Monster info)
{
Debug.Log(info.gameObject.name +"死了,增加金币");
}
}