消息机制讲解


title: 消息机制
date: 2022-11-21 22:25:57
tags#

这篇文章希望能够教会你们一种构建简单Unity框架,使Unity的各个模块能够通信,特别是用在UI上的通信,在实现代码高度解耦的情况下,使不同的UIPanel,之间能够互相调用通信,即和其他模块联动

消息机制的大致类图

AreaCode

通知各个模块的消息码

    /// <summary>
    /// UI模块
    /// </summary>
    public const int UI = 0;

    /// <summary>
    /// GAME模块
    /// </summary>
    public const int GAME = 1;

    /// <summary>
    /// CHARACTER模块
    /// </summary>
    public const int CHARACTER = 2;

    /// <summary>
    /// NET模块
    /// </summary>
    public const int NET = 3;

    /// <summary>
    /// AUDIO模块
    /// </summary>
    public const int AUDIO = 4;

    /// <summary>
    /// SCENE模块
    /// </summary>
    public const int SCENE = 5;

MonoBase

MonoBase 脚本用来拓展 MonoBehaviour ,使每一个继承MonoBase 的脚本都能有MonoBase中的方法

public class MonoBase : MonoBehaviour 
{
    /// <summary>
    /// 定义一个虚方法
    /// </summary>
    public virtual void Execute(int eventCode, object message)
    {
        
    }
}

ManagerBase(重点)

用来绑定和解绑消息码,继承MonoBase , 也是其他模块 Manager脚本的父类

ManagerBase 具有一个字典用来存放 消息码 和 绑定了此消息的脚本

private Dictionary<int,List<MonoBase>> dict = new Dictionary<int, List<MonoBase>>();

要怎么才能让消息码绑定对应的脚本

我们定义一个 add 方法 用来绑定消息

// 为什么存放脚本的类型是 MonoBase 因为 消息码会有很多给,要定义不同的脚本,此时我们需要一个父类来统一这些脚本
public void Add(int eventCode , MonoBase mono)
{
    // 存放脚本的链表
    List<MonoBase> list = null;
    // 先判断这个消息码有没有绑定过脚本
	if(dict.ContainsKey(eventCode))
    {
        list = new List<MonoBase>();
        list.add(mono);
        dict.add(eventCode,mono);
        // 此时就形成了一个消息码和与之对应脚本列表的绑定,在后面我们要通知这些脚本时,只需要遍历这些脚本
    }
    // 如果之前已经有脚本绑定了这个消息码
    else{
        // 从字典中取出这个链表,把这个脚本加到这个链表中去
        list = dict[eventCode];
        list.add(mono);
    }
}

// 定义一个Add的重载方法,用来与模块那边匹配
public void Add(int[] eventCode,MonoBase mono)
{
    for(int i = 0; i< eventCode.Length; i++)
    {
        add(eventCode[i],mono);
    }
}

定义解绑消息的方法 Remove

// 和 Add 方法类似   
public void Remove(int eventCode, MonoBase mono)
{
    //没注册过 没法移除 报个警告
    if (!dict.ContainsKey(eventCode))
    {
        Debug.LogWarning("没有这个事件" + eventCode + "注册");
        return;
    }

    List<MonoBase> list = dict[eventCode];

    if (list.Count == 1)
        dict.Remove(eventCode);
    else
        list.Remove(mono);
}

public void Remove(int[] eventCodes, MonoBase mono)
{
    for (int i = 0; i < eventCodes.Length; i++)
    {
        Remove(eventCodes[i], mono);
    }
}

脚本执行 消息码的方法

// MonoBase 让这些脚本都一个同名的执行方法
public virtual void Execute(int eventCode, object message)
{
    // 没有脚本绑定过这个消息码
	if(!dict.ContainsKey[eventCode])
        return;
    else
    {
        // 字典取出 绑定了脚本
        list<MonoBase> list = dict[eventCode];
		// for 循环 依次执行
        for(int i = 0; i< list.Count ; i++)
        {
            // 调用脚本自身的Execute方法来执行具体方法
            list[i].Execute(eventCode,message);
        }
    }
}

MsgCenter

将各个模块联系起来转发消息

// 制造单例模式
public static MsgCenter Instance;

privare void Awake()
{
	gameObject.AddComponent<>();
}

// 消息转发中心,具体每个模块只要调用这个方法,传入areaCode 等参数就可以将消息通知到其他模块
private void Dispatch(int areaCode , int eventCode, object message)
{
    switch(areaCode)
    {
        case AreaCode.UI:
            UIManager.Instance.Execute(eventCode,message); // UIManager 有什么用会在后面的UI模块里面讲解 
            break;
        case AreaCode.Scenes:
            ScenesManager.Instance.Execute(eventCode,message);
            break;
       	// 还有很多模块 ····
    }
}

这样我们就写完这个框架的主体内容,剩下的就是编写各个模块对应 Manager , 用每个模块的Manager脚本来维护 各个模块的信息

UI 模块

UIManager

*UIManager 继承ManagerBase有 ManagerBase 的绑定,解绑,执行方法,UIManager 在调用这些方法时也维护了自身的字典来保存脚本信息,这样就起到了区分各个模块的作用

public static UIManager Instance;
// 构造单例,因为保存脚本的字典只能是唯一
public void Awak()
{
	Instance = this;
}

UIBase

UIBase 是UI模块具体类的父类,通过调用UIManager 和 MsgCenter这个单例来实现消息的绑定和转发

UIBase 继承 MonoBase

// 脚本消息的链表,因为会有很多UI脚本继承UIBase 他们绑定的消息码最终都会发到CodeList里面
public List<int> CodeList = new List<int>CodeList;

public void Bind(int[] eventCode)
{
	CodeList.addRangeeventCode);
    // 单例调用UI模块的Manager 来把消息码和对应的脚本发给 ManagerBase
	UIManager.Instance.Add(CodeList.ToArray(),this);
}

public void UnBind()
{
	UIManager.Instance.Remove(CodeList.ToArray(), this);
	CodeList.Clear();
}
// OnDestroy 函数在游戏结束时自动调用用来接触绑定
public  virtual void OnDestroy()
{
    if (list != null)
        UnBind();
}
// 发送消息
public void Dispatch(int areaCode, int eventCode, object message)
{
    MsgCenter.Instance.Dispatch(areaCode, eventCode, message);
}


总结

这个消息框架,主要就是将游戏分为各个模块,将每个模块想象成一个单独的城市,每个城市有一个Manager 如 UIManager , 消息码 相当于地址来区别 正真的消息 object message 发往何处。MsgCents 则相当于一个中转站,识别 消息码 发往何处。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值