1.问题的引入
假设场景中有这样几个GameObject:
我们需要实现的是在Monster死亡时,让Player经验值增加,Task处理任务进度,Other处理其他怪物死后该做的事情
那么这个代码大概是:
public void MonsterDead()
{
GameObject.Find("Task").GetComponent<Task>().TaskDoWhenMonsterDead();
GameObject.Find("Other").GetComponent<Other>().OtherDoWhenMonsterDead();
GameObject.Find("Player").GetComponent<Player>().PlayDoWhenMonsterDead();
}
需要找到其他的各个GameObject,获取脚本,然后再调用函数,如果还有其他的一大堆GameObject要响应这个事件(耦合度高),或者是其他GameObject也需要这样调用另外的GameObject的脚本函数,可以说很麻烦了。
这个时候就需要引入事件中心。
2.事件中心:
大致思路:当怪物死后,向事件中心发出一个消息(怪物挂了),这些需要响应的GameObject中的函数做成一个多播委托由事件中心调用来响应这个消息。
3.编码:
数据结构:这个发出的消息可以用String来存放,而委托则用unity自带的UnityAction即可,在调用时可能需要传参,参数类型可设置为万能的Object,由于这些消息和委托一一对应,即可用键值对的方式(Dictionary)表示,则可以表示为:
Dictionary<string,UnityAction<Object>> dic = new Dictionary<string, UnityAction<Object>>();
整个事件中心代码:
public class EventCenter : SingeCaseBase<EventCenter>
{
Dictionary<string,UnityAction<Object>> dic = new Dictionary<string, UnityAction<Object>>();
/// <summary>
/// 添加监听事件
/// </summary>
/// <param name="eventName"></param>
/// <param name="action"></param>
public void AddEventListener(string eventName,UnityAction<Object> action)
{
if(dic.ContainsKey(eventName))
{
dic[eventName] += action;
}
else
{
dic.Add(eventName, action);
}
}
/// <summary>
/// 当事件触发
/// </summary>
/// <param name="evenName"></param>
public void EventTrigger(string eventName,Object info)
{
if(dic.ContainsKey(eventName))
{
dic[eventName](info);
}
}
/// <summary>
/// 移除委托
/// </summary>
/// <param name="eventName"></param>
/// <param name="action"></param>
public void RemoveAction(string eventName,UnityAction<Object> action)
{
if(dic.ContainsKey(eventName))
{
dic[eventName] -= action;
}
}
/// <summary>
/// 清空所有事件
/// </summary>
public void Clear()
{
dic.Clear();
}
}
}
以Player的响应为例:
public class Player : MonoBehaviour
{
private void Start()
{
EventCenter.GetInstance().AddEventListener("MonsterDead", PlayDoWhenMonsterDead);
}
public void PlayDoWhenMonsterDead(Object info)
{
Debug.Log("The Player Adds Exp"+ (info as Monster).addExp);
}
/// <summary>
/// 死亡时移除对应委托【特别注意】
/// </summary>
private void OnDestroy()
{
EventCenter.GetInstance().RemoveAction("MonsterDead", PlayDoWhenMonsterDead);
}
}
注意:一定要注意在物体Destroy时移除委托,在场景切换时清空所有事件