[Unity 代码写法整理]消息机制(三)

本文详细解析了游戏开发中两种消息传递机制的实现方式,包括即时消息和队列消息的处理流程,以及如何通过枚举区分消息类型。探讨了消息中心的架构设计,从消息体、处理函数到消息注册、注销及发送的全过程。并提出了使用接口代替委托以统一消息处理的方法。

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

实现第二种即时的消息机制,写法的话跟第一种几乎一样,只是去掉了Queue并且在消息发出时执行Handler

==============================

1.消息体 AbstractMessage:

  public abstract class AbstractMessage
  {
      public string messageName;
  }

同第一种

 ==============================

2.消息处理函数Handler:

Action<AbstractMessage> handler

同第一种

 ==============================

3.消息中心MessageCenter在第一种的基础上做一些修改

public class MessageCenter : MonoSingleton<MessageCenter>
{
    private Dictionary<string,Action<AbstractMessage>> messageDic = new Dictionary<string,Action<AbstratMessage>>();
 
    //HandleMessage 处理发送的消息
    private void HandleMessage(AbstractMessage message)
    {
        string messageName = message.messageName;
        if(messageDic.ContainsKey(messageName))
        {
            messageDic[messageName](message);
            return;
        }
        Debug.LogError("This message has not registed : " + message.messageName);
    }
 
    //RegistMessage 注册消息
    public void RegistMessage(string messageName,Action<AbstractMessage> handler)
    {
        if(messageDic.ContainsKey(messageName))
        {
            messageDic[messageName] += handler;
            return;
        }
        messageDic[messageName] = handler;
    }    
 
    //UnRegistMessage 注销消息
    public void UnRegistMessage(string messageName,Action<AbstractMessage> handler)
    {
        if(messageDic.ContainsKey(messageName))
        {
            if(messageDic[messageName].GetInvocationList().Length > 1)
            {
                messageDic[messageName] -= handler;
                return;
            }
            messageDic.Remove(messageName);
            return;
        }
        Debug.LogError("This Message Not Registed : " + messageName);
    }
 
    //DispatchMessage 发消息
    public void DispatchMessage(AbstractMessage message)
    {
        HandleMessage(message);
    }
}

相当于是第一种消息中心的简化,MessageQueue理论上来说,并不需要单例类继承Monobehaviour了,因为不需要Update去实现Loop检测消息功能。但是考虑到可以将两种消息机制合二为一,所以还是继承MonoSingleton。

 ==============================

4.在对消息机制的实际运用中,只有三种方法需要运用到,也就是MessageCenter里的注册、注销、发送消息。而两种消息机制除了发送消息,其他并没有区别,也就是说,可以给发送消息再添加一个参数,以区分这两种消息种类,我比较偏向于使用枚举来实现。

public enum DispatchMessageType
{
    Immediate,    //发送即时消息
    Queued    //发送队列消息
}


public class MessageCenter : MonoSingleton<MessageCenter>
{
    private Dictionary<string,Action<AbstractMessage>> messageDic = new Dictionary<string,Action<AbstratMessage>>();
 
    private Queue<AbstractMessage> messageQueue = new Queue<AbstractMessage>();
 
    //Call per frame
    private void Update()
    {
        while(messageQueue.Peek() != null)
        {
            AbstractMessage message = messageQueue.Dequeue();
            HandleMessage(message);
        }
    }
 
    //HandleMessage 处理发送的消息
    private void HandleMessage(AbstractMessage message)
    {
        string messageName = message.messageName;
        if(messageDic.ContainsKey(messageName))
        {
            messageDic[messageName](message);
            return;
        }
        Debug.LogError("This message has not registed : " + message.messageName);
    }
 
    //RegistMessage 注册消息
    public void RegistMessage(string messageName,Action<AbstractMessage> handler)
    {
        if(messageDic.ContainsKey(messageName))
        {
            messageDic[messageName] += handler;
            return;
        }
        messageDic[messageName] = handler;
    }    
 
    //UnRegistMessage 注销消息
    public void UnRegistMessage(string messageName,Action<AbstractMessage> handler)
    {
        if(messageDic.ContainsKey(messageName))
        {
            if(messageDic[messageName].GetInvocationList().Length > 1)
            {
                messageDic[messageName] -= handler;
                return;
            }
            messageDic.Remove(messageName);
            return;
        }
        Debug.LogError("This Message Not Registed : " + messageName);
    }
 
    //DispatchMessage 发消息
    public void DispatchMessage(AbstractMessage message,DispatchMessageType typeEnum)
    {
        switch(typeEnum)
        {
            case DispatchMessageType.Immediate: 
                HandleMessage(message);
                break;
            case DispatchMessageType.Queued:
                messageQueue.Enqueue(message);
                break;
            default:break;
        }
    }
}

这样就将即时消息和队列消息合二为一,组成了一个完整的消息中心。

 ==============================

5.最后补充一下,因为现在所使用的Handler都是委托类型,如果将其改为接口,则可以在一个类中实现接口中的函数配合switch以达成统一处理消息的目的。比如定义一个接口IMessageHandler。

public interface IMessageHandler
{
    void OnReceiveMessage(AbstractMessage message);
}

然后将MessageCenter里面所有的Action<AbstractMessage>全部替换为IMessageHandler(懒得上代码)

这样的话,假如一个类需要接收消息,继承此接口即可

public class Test : Monobehaviour,IHandleMessage
{
    public void OnReceiveMessage(AbstractMessage message)
    {
        switch(message.messageName)
        {
            case "message1":
                //do something
                break;
            //case ...
        }
    }
}

或者再封装一层Monobehaviour,提供注册和注销函数。

public abstract MessageMonobehaviour : MonoBehaviour,IHandler
{
    protected virtual void RegistMessage(string MessageName)
    {
        //由于委托替换为接口,直接用this即可
        MessageCenter.Instance.RegistMessage(MessageName,this);
    }

    protected virtual void UnRegistMessage(string MessageName)
    {
        //由于委托替换为接口,直接用this即可
        MessageCenter.Instance.UnRegistMessage(MessageName,this);
    }

    //子类重写此方法以处理消息
    public virtual void OnReceiveMessage(AbstractMessage message)
    {
        Debug.Log(this.GetType() + " ReceiveMessage, MessageName : " + message.messageName);
    }
}

 ==============================

没了,消息机制应该就这么多,想到了再补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值