第4种:消息传递系统。任何游戏对象都可以通过该系统把消息传递给任何可能该消息感兴趣的对象。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
* Author:W
* 消息系统
*/
/// <summary>
/// 消息基本类型
/// </summary>
public class Msg
{
public string type;
public Msg() {
type = this.GetType().Name;
}
}
/// <summary>
/// 侦听器回调类型定义
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public delegate bool OnMsgHandlerDelegate(Msg msg);
/// <summary>
/// 游戏消息传递系统
/// </summary>
public class MessageSystem : MonoSingleton<MessageSystem> {
/// <summary>
/// 游戏消息侦听回调列表
/// </summary>
private Dictionary<string, List<OnMsgHandlerDelegate>> msgListenerDict = new Dictionary<string, List<OnMsgHandlerDelegate>>();
/// <summary>
/// 限制当前帧处理时间的阔值,超过该值,游戏可能会出现卡顿,我们可以通过该检测指标
/// 来衡量是否暂停当前帧的消息的处理,剩下的消息留到下一帧来继续处理
/// </summary>
private const int maxQueueProcessTime = 16667;
private System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
/// <summary>
/// 待处理的消息队列
/// </summary>
private Queue<Msg> QueueMsgs = new Queue<Msg>();
/// <summary>
/// 将要传递的消息压入消息队列中【性能优化版的消息处理】
/// 比较适合对当前帧不那么重要的消息。
/// </summary>
/// <param name="msg"></param>
public void EnqueueMsg(Msg msg)
{
if (!msgListenerDict.ContainsKey(msg.type))
{
return;
}
QueueMsgs.Enqueue(msg);
}
void Update()
{
timer.Start();
while (QueueMsgs.Count > 0)
{
//当前帧消息处理时间超过我们预设的阔值,说明会影响到游戏的流畅,此时应该终止当前帧对消息的
//继续处理
if (maxQueueProcessTime > 0)
{
if (timer.Elapsed.Milliseconds > maxQueueProcessTime)
{
timer.Stop();
return;
}
}
Msg curMsg = QueueMsgs.Dequeue();
//当前消息处理
TrigeerMsg(curMsg);
}
}
/// <summary>
/// 消息处理【立即处理消息】
/// 特点:对帧率影响比较大
/// 比较适合需要立马处理地消息,否则会导致奇怪的现象发生。
/// </summary>
/// <param name="msg"></param>
public void TrigeerMsg(Msg msg)
{
string typeName = msg.type;
if (!msgListenerDict.ContainsKey(typeName))
{
Debug.Log("消息列表中没有该类型的消息");
return;
}
List<OnMsgHandlerDelegate> onMsgHandlerDelegates = msgListenerDict[typeName];
for (int i = 0; i < onMsgHandlerDelegates.Count; i++)
{
onMsgHandlerDelegates[i](msg);
}
}
/// <summary>
/// 消息监听注册
/// </summary>
/// <param name="msgType"></param>
/// <param name="onMsgHandlerDelegate"></param>
public void AddMsgListener(System.Type msgType, OnMsgHandlerDelegate onMsgHandlerDelegate)
{
if (msgType == null)
{
Debug.Log("消息类型为Null,消息侦听注册不上");
return;
}
string typeName = msgType.Name;
if (!msgListenerDict.ContainsKey(typeName))
{
msgListenerDict.Add(typeName,new List<OnMsgHandlerDelegate>());
}
List<OnMsgHandlerDelegate> onMsgHandlerDelegates = msgListenerDict[typeName];
if (onMsgHandlerDelegates.Contains(onMsgHandlerDelegate))
{
Debug.Log("该侦听回调已经注册了,无需重复注册");
return;
}
onMsgHandlerDelegates.Add(onMsgHandlerDelegate);
}
/// <summary>
/// 消息监听注销
/// </summary>
/// <param name="msgType"></param>
/// <param name="onMsgHandlerDelegate"></param>
public void RemoveMsgListener(System.Type msgType, OnMsgHandlerDelegate onMsgHandlerDelegate)
{
if (msgType == null)
{
Debug.Log("消息类型为Null,注销失败!");
return;
}
string typeName = msgType.Name;
if (!msgListenerDict.ContainsKey(typeName))
{
Debug.Log("没有该消息的侦听回调,注销失败!");
return;
}
List<OnMsgHandlerDelegate> onMsgHandlerDelegates = msgListenerDict[typeName];
if (!onMsgHandlerDelegates.Contains(onMsgHandlerDelegate))
{
Debug.Log("该消息的侦听回调列表中没有该回调,注销失败!");
return;
}
onMsgHandlerDelegates.Remove(onMsgHandlerDelegate);
}
}
总结:这是优化版的消息传递分发系统。需要立马处理的消息使用TriggerMsg()接口;对及时性或当前帧影响不大的,推荐使用EnqueueMsg()接口。后者对性能比较友好。