1、前言
目前脚本之间的交互有下面三种常用方式:
- 通过GetComponent<脚本>().Method();
- 单例模式传递数据
- 脚本组件的SendMessage方法
这三种方式,耦合性都很高;第三种方式由于是通过反射实现的,所以效率很低,还存在很多隐患,因为不知道哪一天,新接手这代码的程序员就可能把那个方法删了而产生新的bug。
2、消息分发机制
下面通过委托与事件来实现一个消息分发功能
using System.Collections.Generic;
public class MsgHandler
{
public delegate void DelMsgHandler(Msg msg);
private static Dictionary<string, DelMsgHandler> mDicMsgs = new Dictionary<string, DelMsgHandler>();
//添加监听者
public static void AddListener(string msgType, DelMsgHandler handler)
{
//判空
if (mDicMsgs == null) mDicMsgs = new Dictionary<string, DelMsgHandler>();
if (!mDicMsgs.ContainsKey(msgType)) mDicMsgs.Add(msgType, null);
//增加监听
mDicMsgs[msgType] += handler;
}
/// <summary>
/// 去除对参数handler的监听
/// </summary>
/// <param name="msgType">消息类型</param>
/// <param name="handler">被监听方法</param>
public static void RemoveListener(string msgType, DelMsgHandler handler)
{
if (mDicMsgs != null && mDicMsgs.ContainsKey(msgType)) mDicMsgs[msgType] -= handler;
}
/// <summary>
/// 清除所有的监听者
/// </summary>
public static void ClearAllListeners()
{
if (mDicMsgs != null) mDicMsgs.Clear();
}
/// <summary>
/// 分发消息
/// </summary>
/// <param name="msgType">消息类型</param>
/// <param name="msg">分发的内容</param>
public static void SendMsg(string msgType, Msg msg)
{
DelMsgHandler handler;
if (mDicMsgs != null && mDicMsgs.TryGetValue(msgType, out handler))
{
if (handler != null)
handler(msg);
}
}
}
public class Msg
{
public string Key { get; private set; }
public object Value { get; private set; }
public Msg(string key, object value)
{
this.Key = key;
this.Value = value;
}
}
3、脚本组件的使用方式
测试脚本1:Test1.cs
using UnityEngine;
public class Test1 : MonoBehaviour
{
private void Awake()
{
//1、通过lambda表达式,如果代码量只有几行,用这个比较方便
//MsgHandler.AddListener("Test1", (msg) => { });
//2、通过方法,代码量多时用
MsgHandler.AddListener("Test1", HandleMsg);
}
/// <summary>
/// 处理消息
/// </summary>
/// <param name="msg">消息</param>
private void HandleMsg(Msg msg)
{
switch (msg.Key)
{
case "msg key":
Debug.Log(msg.Value);
break;
default:
Debug.Log("ERROR KEY:" + msg.Key);
break;
}
}
private void OnDestroy()
{
//在脚本被销毁之前,要清除这个监听器
MsgHandler.RemoveListener("Test1", HandleMsg);
}
}
测试脚本2:Test2.cs
using UnityEngine;
public class Test2 : MonoBehaviour
{
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
//发送消息类型为“Test1”的消息
MsgHandler.SendMsg("Test1", new Msg("msg key", "msg value"));
}
}
}
将这两个脚本分别挂载在两个游戏物体上,运行程序,点击鼠标即可在控制台中输出日志信息:msg value
注意:一定要在OnDestory()中移出监听器,理由是:假如没有销毁,在脚本A在A场景中使用了,在B场景中也使用了, 那么当A场景跳转至B场景时,然后再发消息给脚本A,那么脚本A就会收到2条消息