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