之前有看到一个老哥用List做了一个定时器管理器,使用过程中发现了些问题,接下来我用字典重构了下,测试后解决了存在的时序bug.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
///
/// 定时器
///
/// 使用案例:
///
/// Timer.SetTimeout(1.0f, () =>
/// {
/// Debug.Log("after 1 second.");
/// });
///
///
/// int i = 0;
/// Timer.SetInterval(1.0f, () =>
/// {
/// Debug.Log(i++);
/// }, 10);
///
/// </summary>
public class Timer : MonoBehaviour
{
protected static Dictionary<int, TimerComponent> _componentsDic = new Dictionary<int, TimerComponent>();
protected static int _tagCount = 1000;
private bool isBackground = false;//是否可以后台运行
//Update更新之前
private void Start()
{
StartCoroutine(UpdateFrame());
}
//程序切换到后台
private void OnApplicationPause(bool pause)
{
if (pause)
{
if (!isBackground)
StopAllCoroutines();
}
else
{
if (!isBackground)
StartCoroutine(UpdateFrame());
}
}
//每一帧都更新
private IEnumerator UpdateFrame()
{
while (true)
{
if (_componentsDic.Count > 0)
{
float dt = Time.deltaTime;
TimerComponent t = null;
for (int i = 0; i < _componentsDic.Count; i++)
{
KeyValuePair<int, TimerComponent> kv = _componentsDic.ElementAt(i);
t = kv.Value;
t.tm += Time.deltaTime;
if (t.tm >= t.life)
{
t.tm -= t.life;
Debug.LogError("------ " + _componentsDic.Count);
_componentsDic.Remove(kv.Key);
t.func();
}
}
}
yield return 0;
}
}
/// <summary>
/// 延时回调一次
/// </summary>
/// <param name="delay">等待时间 单位秒</param>
/// <param name="func">回调方法</param>
/// <returns>Timer ID</returns>
public static int SetTimeout(float delay, Action func)
{
return SetInterval(delay, func);
}
/// <summary>
/// 注册一个定时器
/// </summary>
/// <param name="interval">间隔 单位秒</param>
/// <param name="func">调度方法</param>
/// <param name="times">循环次数 times{ 0 | < 1 }:一直循环 </param>
/// <returns>每个调度器的标签值</returns>
public static int SetInterval(float interval, Action func, int times = 1)
{
var scheduler = new TimerComponent();
scheduler.tm = 0;
scheduler.life = interval;
scheduler.func = func;
scheduler.count = times;
scheduler.tag = ++_tagCount;
_componentsDic[scheduler.tag] = (scheduler);
if (!_inited) Init();
return _tagCount;
}
/// <summary>
/// 通过Tag获取定时器对象
/// </summary>
/// <param name="tag"></param>
/// <returns></returns>
public static TimerComponent GetTimer(int tag)
{
foreach (var scheduler in _componentsDic.Keys)
{
if (tag == _componentsDic[scheduler].tag)
{
return _componentsDic[scheduler];
}
}
return null;
}
/// <summary>
/// 清理定时器
/// </summary>
/// <param name="tag">定时器标签</param>
/// <returns></returns>
public static void ClearTimer(int tag)
{
if (_componentsDic.ContainsKey(tag))
{
_componentsDic.Remove(tag);
}
Debug.LogError("ClearTimer " + tag + " " + _componentsDic.Count);
}
/// <summary>
/// 清理所有定时器
/// </summary>
public static void ClearTimers()
{
_componentsDic.Clear();
}
//初始化
protected static bool _inited = false;
protected static void Init()
{
var inst = new GameObject("TimerNode");
inst.AddComponent<Timer>();
_inited = true;
}
}
//定时器数据类
public class TimerComponent
{
public int tag;
public float tm;
public float life;
public int count;
public Action func;
}