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);
}
}