using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// 游戏定时器
/// </summary>
public class GameTimer : MonoBehaviour
{
public static GameTimer Instance { get; private set; }
private List<Context> contexts = new List<Context>();
private void Awake()
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
private void OnDestroy()
{
Clear();
Instance = null;
}
void Update()
{
for (int i = 0; i < contexts.Count; i++)
{
var ctx = contexts[i];
if (ctx == null || ctx.action == null)
{
contexts.RemoveAt(i);
break;
}
if (ctx.triggerTime <= Time.time)
{
if (ctx.repeating)
{
ctx.action?.Invoke(ctx.p);
ctx.triggerTime = Time.time + ctx.interval;
}
else
{
//必须先RemoveAt,因为回调函数中可能会进行注册或移除操作,导致索引错位。
contexts.RemoveAt(i);
ctx.action?.Invoke(ctx.p);
ctx.action = null;
ctx.p = null;
i--;
}
break;
}
}
}
private void Register(Context context)
{
if (context == null || context.action == null)
return;
//如果triggerTime未设值
if (context.triggerTime < 0)
context.triggerTime = Time.time + context.duration;
contexts.Add(context);
Debug.LogFormat("[GameTimer] Register {0}", context.action.Method.Name);
}
//注册定时器方法
public void Register(UnityAction<object> action, float duration = 1.0f, object p = null)
{
if (action == null)
return;
Context context = new Context();
context.action = action;
context.duration = duration;
context.p = p;
Register(context);
}
//注册定时器方法(按间隔时间重复调用)
public void RegisterRepeating(UnityAction<object> action, float duration = 1.0f, float interval = 1.0f, object p = null)
{
Context context = new Context();
context.action = action;
context.duration = duration;
context.interval = interval;
context.p = p;
context.repeating = true;
Register(context);
}
//移除定时器方法
public void Remove(UnityAction<object> action)
{
if (action == null)
return;
for (int i = 0; i < contexts.Count; i++)
{
var ctx = contexts[i];
if (ctx == null || ctx.action == null)
continue;
if (ctx.action.GetHashCode() == action.GetHashCode())
{
Debug.LogFormat("[GameTimer] Remove {0}", ctx.action.Method.Name);
ctx.action = null;
contexts.RemoveAt(i);
i--;
}
}
}
//清空
public void Clear()
{
for (int i = 0; i < contexts.Count; i++)
{
var ctx = contexts[i];
if (ctx == null)
continue;
ctx.action = null;
ctx.p = null;
}
contexts.Clear();
}
private class Context
{
//定时器回传参数
public object p;
//回调方法
public UnityAction<object> action;
//延迟调用
public float duration = 1f;
//调用间隔时间
public float interval = 1f;
//是否重复调用
public bool repeating = false;
//触发时间(Time.time + x)
public float triggerTime = -1f;
}
}