1. 场景与脚本设置
- 场景描述:怪物死亡后,玩家脚本执行信息,任务脚本执行信息,以及执行其他信息。新建
Monster
Player
Task
Other
四个脚本。
Monster
脚本
public class Monster : MonoBehaviour
{
public string sname = "怪物x";
// Start is called before the first frame update
void Start()
{
Dead();
}
void Dead()
{
Debug.Log("怪物死亡!");
GameObject.Find("Player").GetComponent<Player>().MonsterDead(this);
GameObject.Find("Task").GetComponent<Task>().TaskmonsterDead(this);
GameObject.Find("Other").GetComponent<Other>().OthermonsterDead(this);
}
}
Player
脚本
public class Player : MonoBehaviour
{
public void MonsterDead(Object info) {
Debug.Log("玩家得奖励!"+(info as Monster).sname);
}
}
Task
脚本
public class Task : MonoBehaviour
{
public void TaskmonsterDead(Object info)
{
Debug.Log("任务信息!" + (info as Monster).sname);
}
}
Other
脚本
public class Other : MonoBehaviour
{
public void OthermonsterDead(Object info)
{
Debug.Log("做其他工作!" + (info as Monster).sname);
}
}
- 脚本挂载,分别挂载对应的游戏物体上。
- 运行测试
此种写法增加了脚本之间的耦合度,随着业务逻辑的复杂增加,导致逻辑不清维护难度增大。
2. 引入观察者模式
观察者模式简介
- 模式的定义与特点
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。 - 观察者模式是一种对象行为型模式,其主要优点如下。
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
目标与观察者之间建立了一套触发机制。 - 它的主要缺点如下。
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
3.改写脚本
- 事件中心脚本
EventCenter
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public interface IEventInfo
{
}
public class EventInfo<T> : IEventInfo
{
public UnityAction<T> actions;
public EventInfo( UnityAction<T> action)
{
actions += action;
}
}
public class EventInfo : IEventInfo
{
public UnityAction actions;
public EventInfo(UnityAction action)
{
actions += action;
}
}
/// <summary>
/// 事件中心 单例模式对象
/// 1.Dictionary
/// 2.委托
/// 3.观察者设计模式
/// 4.泛型
/// </summary>
public class EventCenter : BaseManager<EventCenter>
{
//key —— 事件的名字(比如:怪物死亡,玩家死亡,通关 等等)
//value —— 对应的是 监听这个事件 对应的委托函数们
private Dictionary<string, IEventInfo> eventDic = new Dictionary<string, IEventInfo>();
/// <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 EventInfo<T>).actions += action;
}
//没有的情况
else
{
eventDic.Add(name, new EventInfo<T>( action ));
}
}
/// <summary>
/// 监听不需要参数传递的事件
/// </summary>
/// <param name="name"></param>
/// <param name="action"></param>
public void AddEventListener(string name, UnityAction action)
{
//有没有对应的事件监听
//有的情况
if (eventDic.ContainsKey(name))
{
(eventDic[name] as EventInfo).actions += action;
}
//没有的情况
else
{
eventDic.Add(name, new EventInfo(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 EventInfo<T>).actions -= action;
}
/// <summary>
/// 移除不需要参数的事件
/// </summary>
/// <param name="name"></param>
/// <param name="action"></param>
public void RemoveEventListener(string name, UnityAction action)
{
if (eventDic.ContainsKey(name))
(eventDic[name] as EventInfo).actions -= action;
}
/// <summary>
/// 事件触发
/// </summary>
/// <param name="name">哪一个名字的事件触发了</param>
public void EventTrigger<T>(string name, T info)
{
//有没有对应的事件监听
//有的情况
if (eventDic.ContainsKey(name))
{
//eventDic[name]();
if((eventDic[name] as EventInfo<T>).actions != null)
(eventDic[name] as EventInfo<T>).actions.Invoke(info);
//eventDic[name].Invoke(info);
}
}
/// <summary>
/// 事件触发(不需要参数的)
/// </summary>
/// <param name="name"></param>
public void EventTrigger(string name)
{
//有没有对应的事件监听
//有的情况
if (eventDic.ContainsKey(name))
{
//eventDic[name]();
if ((eventDic[name] as EventInfo).actions != null)
(eventDic[name] as EventInfo).actions.Invoke();
//eventDic[name].Invoke(info);
}
}
/// <summary>
/// 清空事件中心
/// 主要用在 场景切换时
/// </summary>
public void Clear()
{
eventDic.Clear();
}
}
通过观察者模式实现事件的注册与更改通知各个具体观察者进行自身状态的更新。
降低了目标与观察者之间的耦合关系。
通过实现泛型接口避免了频繁的装箱拆箱操作。
- 修改
Monster
public class Monster : MonoBehaviour
{
public string sname = "怪物x";
// Start is called before the first frame update
void Start()
{
Invoke("Dead",1);
}
void Dead()
{
Debug.Log("怪物死亡!");
//GameObject.Find("Player").GetComponent<Player>().MonsterDead(this);
//GameObject.Find("Task").GetComponent<Task>().TaskmonsterDead(this);
//GameObject.Find("Other").GetComponent<Other>().OthermonsterDead(this);
EventCenter.GetInstance().EventTrigger("MonsterDead",this);
}
}
- 修改
Player
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
EventCenter.GetInstance().AddEventListener<Monster>("MonsterDead", (o) => {
MonsterDead(o);
});
}
// Update is called once per frame
void Update()
{
}
public void MonsterDead(Object info) {
Debug.Log("玩家得奖励!"+(info as Monster).sname);
}
}
- 修改
Task
public class Task : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
EventCenter.GetInstance().AddEventListener<Monster>("MonsterDead", (o)=> {
TaskmonsterDead(o);
});
}
// Update is called once per frame
void Update()
{
}
public void TaskmonsterDead(Object info)
{
Debug.Log("任务信息!" + (info as Monster).sname);
}
}
- 修改
Other
public class Other : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
EventCenter.GetInstance().AddEventListener<Monster>("MonsterDead", (o) => {
OthermonsterDead(o);
});
}
// Update is called once per frame
void Update()
{
}
public void OthermonsterDead(Object info)
{
Debug.Log("做其他工作!" + (info as Monster).sname);
}
}