Lua监听C#消息

博客围绕项目中Lua监听C#消息展开。指出用事件消息通信可降低代码耦合性,介绍了消息基类NotifyBase用于消息处理,探讨了消息名、方法、参数的存储与关联,以及监听、移除、触发消息的实现,还提及Lua监听事件代码和消息码限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lua监听C#消息

概述

在项目中有时候会出现需要Lua监听C#消息的情况,如进入游戏,我们将进入游戏的代码放在C#,将游戏中的界面代码放在Lua中。选择在C#中调用lua代码的方式是非常不建议的,这样会提高代码的耦合性。那么我们能想到的是与之前一篇博客中提到的一样,使用事件消息来进行通信。

消息基类

关于消息我们有很多种,比如从Lua到C#的,C#之间的,Lua与Lua的。那么我们就需要一个基类NotifyBase来进行消息的处理。消息类型的定义会比较麻烦。
消息中我们有监听时传值,触发时传值。
多个监听中会使用同一个触发值,但他们的监听值无关联

以下两个监听:
__EventMessage:AddNotify("StartGame", RefshAge,{age = 100})	
__EventMessage:AddNotify("StartGame", RefshName,{name = "Sun"})
触发:
LogicalMessageNotify.Instance.Notify(ELogicalMessageType.StartGame, person);

RefshAge能收到的参数为RefshAge(person,age)
RefshName能收到的参数为RefshName(person,name)

此时我们如果从Lua向C#请求监听应该如何存储消息名,方法,参数?

protected List<string> m_ltNotifyNames = null;	 //消息名列表
protected List<List<object>> m_ltNotifyParams = null;  //广播参数列表
protected List<List<LogicalMessageNotifyCallback>> m_NotifyFuncs = null;  //广播回调函数列表
//触发参数不需要列表,在触发的时候直接统一给值就可以了

以上三个列表是如何关联的?
首先我们将Lua传过来的消息获取到消息名,再将消息名与m_ltNotifyNames中的值对比,有就直接获取索引,没有就新建一个塞入后获取索引。
然后我们根据索引从m_ltNotifyParams 中找到该事件的广播参数列表,之前有说到,一个广播消息会对应多个监听,所以监听的参数会有多个,那么此时应该如何将回调参数与回调函数对应?
当添加监听的时候会在该消息的参数列表中加入一个参数,在该消息的回调函数列表中加入一个函数。两者就会属于同一个位置。即能保证参数不错位。

添加监听

添加监听
/// <summary>
    /// 添加监听
    /// </summary>
    /// <param name="funcType"></param>
    /// <param name="func"></param>
    /// <param name="value"></param>
    public void AddNotify(string funcType, LogicalMessageNotifyCallback func, object value = null)
    {
        if (func == null || string.IsNullOrEmpty(funcType) == true) return;

        if (m_ltNotifyNames == null)
        {
            m_ltNotifyNames = new List<string>();
            m_ltNotifyParams = new List<List<object>>();
            m_NotifyFuncs = new List<List<LogicalMessageNotifyCallback>>();
        }

        int index = GlobalConfig.BinaryFind(m_ltNotifyNames, funcType);     //二分查找该事件是否存在于m_ltNotifyNames中
        if (index < 0)
        {
            index = GlobalConfig.BinaryInsert(m_ltNotifyNames, funcType);  //把方法名插入到m_ltNotifyNames数组中
            m_ltNotifyParams.Insert(index, new List<object>());            //每个消息都有参数,参数列表对应的索引与事件名关联
            m_NotifyFuncs.Insert(index, new List<LogicalMessageNotifyCallback>()); //消息回调方法,与事件名关联
        }

        List<LogicalMessageNotifyCallback> list = m_NotifyFuncs[index];

        if (list.Contains(func) == false)   //列表中不存在本次添加的事件
        {
            list.Add(func);
            m_ltNotifyParams[index].Add(value);
        }
        else
        {
            LogManager.LogError("重复注册事件");
        }
    }

移除监听

/// <summary>
    /// 移除监听
    /// </summary>
    /// <param name="funcType"></param>
    /// <param name="func"></param>
    public void RemoveNotify(string funcType, LogicalMessageNotifyCallback func)
    {
        if (func == null) return;
        if (m_ltNotifyNames == null) return;

        int index = GlobalConfig.BinaryFind(m_ltNotifyNames, funcType);

        if (index < 0) return;
        List<LogicalMessageNotifyCallback> list = m_NotifyFuncs[index];
        if (list.Count != 0)
        {
            int i = list.IndexOf(func);
            if (i >= 0)
            {
                list.RemoveAt(i);
                m_ltNotifyParams[index].RemoveAt(i);
            }
        }
    }

触发消息

    /// <summary>
    /// 广播一条消息
    /// </summary>
    /// <param name="funcType"></param>
    /// <param name="value"></param>
    public void Notify(string funcType, object value = null)
    {
        if (m_ltNotifyNames == null) return;

        int index = GlobalConfig.BinaryFind(m_ltNotifyNames, funcType);
        if (index < 0) return;
        List<LogicalMessageNotifyCallback> list = m_NotifyFuncs[index];

        if (list.Count > 0)
        {
            List<object> objList = m_ltNotifyParams[index];
            for (int i = list.Count - 1; i >= 0; i--)
            {
                list[i](value, objList[i]);
            }
        }
    }

然而一些并没有结束!
我们上面做到了消息的监听移除和触发,接下来我们则需要开始写Lua监听事件部分的代码
Lua与C#都需要有消息码来限制传递的是什么消息,这样才能够在项目越来越大的时候使项目看起来不会杂乱。

/// <summary>
/// 消息枚举
/// </summary>
public enum ELogicalMessageType
{
    SYSTEM = 0,
    StartGame,
    Count,
}

在Lua中也做同样的代码进行监听

CSLogicalMessageTypes =
{
	StartGame = "StartGame",
}

在监听类初始化的时候将消息枚举存储到m_list中,不在该枚举中的消息不会进行监听。m_notify 则为上面代码的实力类,用于做真的消息处理,而此类作为消息的筛选。筛选过程根据项目需求自行添加。

 protected List<string> m_list = new List<string>();     //存储监听消息名
    protected NotifyBase m_notify = new NotifyBase();

    public LogicalMessageNotify()
    {
        for (int i = 0; i < (int)ELogicalMessageType.Count; ++i)
        {
            m_list.Add(Enum.GetName(typeof(ELogicalMessageType), i));   //获取到ELogicalMessageType没居中的第i个名字
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值