最近做项目用到消息机,去网上找了找发现很多不错的,可是都是即时传送,没有延迟功能。自己就写了一个带延迟的消息机。
文中的消息机基于wiki上的一个消息机,就不过多说明了,大家可以参考这个:http://wiki.unity3d.com/index.php/Advanced_CSharp_Messenger
关于延迟功能,最开始打算用协程去写,后来发现unity3d很多方法和值只能在主线程中使用,所以单写了一个闹钟类,用来计算时间。
大体思路就是延迟消息传入到闹钟类并排序,闹钟类的update方法进行判断,如果延迟消息时间到了,就发送消息。
下面说一下主要功能的实现
延迟消息类,类里包含延迟的时间,收听者名称和委托的参数
/// <summary> /// 延迟消息类 /// </summary> public class DelayMessage { //延迟时间 public float delayTime; //收听者 public string lis; //参数 public object o; //构造函数 public DelayMessage(string lis, object o,float delayTime) { this.lis = lis; this.o=o; //传递的时间为需要延迟的时间 这里加上当前时间 this.delayTime = delayTime+Time.time; } }
//延迟消息 public static void Broadcase<T>(string lis, T arg0,float timeDelay) { //将事件加入延迟事件队列 TimeClock.AddClock( new DelayMessage(lis, arg0,timeDelay)); }
//闹钟 static List<DelayMessage> clockQueue = new List<DelayMessage>(100);
//添加闹钟 public static void AddClock(DelayMessage dm) { //添加闹钟 clockQueue.Add( dm); //排序 clockQueue = (from entry in clockQueue orderby entry.delayTime ascending select entry).ToList(); //获得最小时间 firstKeysSort(); }将延迟的消息加入到集合中 ,并且用linq进行排序,排序依据为delayTime。
firstKeySort方法:
//最小时间 private static float firstKey; //最小时间集合 有多个最小时间时出现 private static List<float> firstKeys; //获得最小时间集合 private static void firstKeysSort() { if (clockQueue.Count == 0) return; //取最小时间 firstKey = (from d in clockQueue orderby d.delayTime ascending select d.delayTime).First(); if(firstKeys!=null) firstKeys.Clear(); // 最小时间可能为多个 所以用集合存储最小时间 firstKeys = (from d in clockQueue where d.delayTime == firstKey select d.delayTime).ToList(); }因为可能会在同一时间传入多个延迟时间相同的消息,所以使用一个集合来记录离当前时间最近的延迟时间
void Update() { //如果没有闹钟返回 if (clockQueue.Count == 0) return; ////闹钟时间到 if (Time.time >= firstKeys[0]) { foreach (float t in firstKeys) { //发送延迟消息 DelayMessage dm = clockQueue[0]; NotificationCenter.Broadcase(dm.lis, dm.o); //移除闹钟 clockQueue.Remove(clockQueue[0]); } //重新获得最小时间 firstKeysSort(); } }时间到后会发送消息,发送完后移除消息集合中的消息,同时重新计算下一个最小时间。
注:初学者,可能有不对之处希望大家指正。消息类还没有完善,如果场景转换的话可能得重置收听者,如果以后有时间会完善。