zl程序教程

您现在的位置是:首页 >  云平台

当前栏目

Unity 工具类 之 简单的消息机制 MessageCenter 实现

消息工具 实现 简单 机制 Unity
2023-09-11 14:20:50 时间

Unity 工具类 之 简单的消息机制 MessageCenter 实现

 

目录

Unity 工具类 之 简单的消息机制 MessageCenter 实现

一、简单介绍

二、实现原理

三、注意事项

四、效果预览

五、实现步骤

六、关键代码


 

一、简单介绍

Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发。

消息机制,也可以叫做观察者设计模式;通俗易懂点讲,就是 一个物体发出消息,另外一个,或者几个物体可以同时接收到这一消息并作出各自不同的行为(反馈,处理)。

 

二、实现原理

1、消息机制中引入了事件机制,事件机制其实是一种叫做观察者模式的设计模式,事件的本质是一种方法的委托(Delegate),把回调方法委托到事件管理器,当条件达到时,通过事件key来告诉事件管理器可以执行那些委托的方法。

2、单例类,保证整个场景中只有一个类管理消息;把消息统一在一起注册、发送和移除;

3、MessageCenter.Instance.RegisterListener 注册消息;

4、MessageCenter.Instance.SendMessage 发送消息;

5、MessageCenter.Instance.RemoveListener 移除消息;

 

三、注意事项

1、为了避免 MessageCenter 单例被 new ,所以在 MessageCenter 中把 无参构造函数私有化;

2、一个消息可注册多个事件;

 

四、效果预览

 

五、实现步骤

1、打开Unity,新建一个工程,如下图

 

2、在工程中新建脚本,Singleton 实现单例类,Message 消息(可以根据需要拓展),MessageCenter 消息中心管理消息的注册发送与移除(可以根据需要拓展),Test_MessageCenter 测试消息机制脚本、如下图

 

3、在场景中添加测试脚本,进行消息机制的测试,如下图

 

4、测试效果如下图

 

六、关键代码

1、Singleton

using System;
using System.Reflection;

/// <summary>
/// 单例
/// 继承需要一个非公有的无参构造函数
/// </summary>
/// <typeparam name="T">类名的泛型</typeparam>
public abstract class Singleton<T> where T : class
{
    private static T instance = null;

    // 多线程安全机制
    private static readonly object locker = new object();

    public static T Instance
    {
        get
        {
            // 线程锁
            lock (locker)
            {
                if (null == instance)
                {
                    // 反射获取实例
                    var octors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic) ;

                    // 获取无参数的非公共构造函数
                    var octor = Array.Find(octors, c => c.GetParameters().Length == 0);

                    // 没有则提示没有私有的构造函数
                    if (null == octor)
                    {
                        throw new Exception("No NonPublic constructor without 0 parameter");
                    }

                    // 实例化
                    instance = octor.Invoke(null) as T;
                }

                return instance;

            }
        }
    }

    /// <summary>
    /// 构造函数
    /// 避免外界new
    /// </summary>
    protected Singleton() { }
}

 

2、Message



/// <summary>
/// 消息类
/// </summary>
public class Message
{
    public int Type  //发送的消息类型
    {
        get;
        private set;
    }
    public object Body  //消息主体
    {
        get;
        private set;
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="type">消息类型</param>
    /// <param name="body">消息体</param>
    public Message(int type, object body)
    {
        Type = type;
        Body = body;
    }
}

 

3、MessageCenter


using System;
using System.Collections.Generic;
using System.Diagnostics;

/// <summary>
/// 消息的类型  
/// </summary>
public enum MessageType
{
    /// <summary>
    /// 启动
    /// </summary>
    START_UP = 1000,
    /// <summary>
    /// 解压
    /// </summary>
    UNPACK,
    /// <summary>
    /// 更新
    /// </summary>
    UPDATE,
    /// <summary>
    /// 更新完成
    /// </summary>
    UPDATE_COMPLETE,
}


/// <summary>
/// 战斗的类型
/// </summary>
public enum BattleEvent
{
    /// <summary>
    /// 攻击
    /// </summary>
    Attack = 10000,
}

/// <summary>
/// 协议的类型
/// </summary>
public enum ProtocolEvent
{

}


/// <summary>
/// 消息中心
/// </summary>
public class MessageCenter : Singleton<MessageCenter>
{
    // 消息委托
    public delegate void messageDelHandle(Message message);
    // 消息字典
    private Dictionary<int, messageDelHandle> messageMap = new Dictionary<int, messageDelHandle>();

    /// <summary>
    /// 构造函数
    /// 避免外界new
    /// </summary>
    private MessageCenter() { }

    /// <summary>
    /// 注册监听
    /// </summary>
    public void RegisterListener(int messageType, messageDelHandle handle)
    {
        if (handle == null) return;

        // 把事件添加到对应的委托中
        messageDelHandle myHandle = null;
        messageMap.TryGetValue(messageType, out myHandle);
        messageMap[messageType] = (messageDelHandle)Delegate.Combine(myHandle, handle);

    }
    /// <summary>
    /// 移除监听
    /// </summary>
    public void RemoveListener(int messageType, messageDelHandle handle)
    {
        if (handle == null) return;
        messageMap[messageType] = (messageDelHandle)Delegate.Remove(messageMap[messageType], handle);
    }

    /// <summary>
    /// 清空消息
    /// </summary>
    public void Clear()
    {
        messageMap.Clear();
    }
    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="messageName">消息类型 </param>
    /// <param name="body"> 发送消息主体 </param>
    public void SendMessage(int messageType, object body = null)
    {

        messageDelHandle handle;
        if (messageMap.TryGetValue(messageType, out handle))
        {
            Message evt = new Message(messageType, body);
            try
            {
                if (handle != null)
                {
                    handle(evt);
                }
            }
            catch (System.Exception e)
            {
                Debug.Print("SendMessage:", evt.Type.ToString(), e.Message, e.StackTrace, e);
            }
        }

    }

    #region 枚举类型接口

    #region MessageType
    public void RegisterListener(MessageType messageType, messageDelHandle handle) {
        RegisterListener((int)messageType, handle);
    }
    public void RemoveListener(MessageType messageType, messageDelHandle handle)
    {
        RemoveListener((int) messageType, handle);
    }
    public void SendMessage(MessageType messageType, object body = null) {
        SendMessage((int)messageType, body);
    }
    #endregion 


    #region BattleEvent
    public void RegisterListener(BattleEvent messageType, messageDelHandle handle)
    {
        RegisterListener((int)messageType, handle);
    }
    public void RemoveListener(BattleEvent messageType, messageDelHandle handle)
    {
        RemoveListener((int)messageType, handle);
    }
    public void SendMessage(BattleEvent messageType, object body = null)
    {
        SendMessage((int)messageType, body);
    }
    #endregion


    #region ProtocolEvent
    public void RegisterListener(ProtocolEvent messageType, messageDelHandle handle)
    {
        RegisterListener((int)messageType, handle);
    }
    public void RemoveListener(ProtocolEvent messageType, messageDelHandle handle)
    {
        RemoveListener((int)messageType, handle);
    }
    public void SendMessage(ProtocolEvent messageType, object body = null)
    {
        SendMessage((int)messageType, body);
    }

    #endregion

    #endregion
}

 

4、Test_MessageCenter

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test_MessageCenter : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        

        MessageCenter.Instance.RegisterListener(MessageType.START_UP, StartUp); //注册
        MessageCenter.Instance.RegisterListener(MessageType.START_UP, StartUp2); //注册
    

    }

    // Update is called once per frame
    void Update()
    {
 
        if (Input.GetKeyDown(KeyCode.A)) {
            
            MessageCenter.Instance.SendMessage(MessageType.START_UP,this.gameObject);
        }

        if (Input.GetKeyDown(KeyCode.D))
        {

            MessageCenter.Instance.RemoveListener(MessageType.START_UP, StartUp2);
        }
    }


    private void StartUp(Message message)
    {
        Debug.Log("游戏启动");
        Debug.Log(message.Type);
        Debug.Log(message.Body);


    }

    private void StartUp2(Message message)
    {
        Debug.Log("游戏启动2");
        Debug.Log(message.Type);
        Debug.Log(message.Body);


    }

}