using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace BallKingdomCrush { public class TimerTask { private Timer timer; public int repeatCount; public float interval; private Action onCallBack; public object[] args; public float time; public bool isActive = true; public bool isFrameUpdate = false; public TimerTask(Timer timer, float interval, Action onCallBack, params object[] args) { this.timer = timer; repeatCount = 1; this.interval = interval; this.onCallBack = onCallBack; this.args = args; time = timer.GetTriggerTime(interval); } public TimerTask(Timer timer, int repeatCount, float interval, Action onCallBack, params object[] args) { this.timer = timer; this.repeatCount = repeatCount; this.interval = interval; this.onCallBack = onCallBack; this.args = args; time = timer.GetTriggerTime(interval); } public TimerTask(Timer timer, Action onCallBack, params object[] args) { this.timer = timer; this.onCallBack = onCallBack; this.args = args; } public void CallFunc() { onCallBack?.Invoke(this); } public static implicit operator bool(TimerTask timerTask) { return null != timerTask; } } public class Timer : MonoBehaviour { public const int INFINITE_LOOP = -1; private List timerTaskList = new(); private List timerTaskTriggers = new(); [SerializeField] private string timerName; private TimerTimeType type = TimerTimeType.Null; public void SetTimer(string name, TimerTimeType type) { this.timerName = name + "_" + type; this.type = type; } private float GetTime() { return type switch { TimerTimeType.Time => Time.time, TimerTimeType.UnscaledTime => Time.unscaledTime, TimerTimeType.RealtimeSinceStartup => Time.realtimeSinceStartup, _ => 0 }; } private void Update() { if (timerTaskList.Count > 0) { timerTaskTriggers.Clear(); foreach (var timerTask in timerTaskList.Where(timerTask => timerTask.isActive)) { if (timerTask.isFrameUpdate) { timerTaskTriggers.Add(timerTask); } else { if (timerTask.time <= GetTime()) { timerTaskTriggers.Add(timerTask); } } } foreach (var triggerTimerTask in timerTaskTriggers) { if (triggerTimerTask.repeatCount != INFINITE_LOOP) { triggerTimerTask.repeatCount--; } if (triggerTimerTask.repeatCount == 0) { timerTaskList.Remove(triggerTimerTask); } else { if (!triggerTimerTask.isFrameUpdate) { triggerTimerTask.time = GetTriggerTime(triggerTimerTask.interval); } } triggerTimerTask.CallFunc(); } } } public TimerTask AddLoopTimer(float interval, Action onCallBack, params object[] args) { var timeTask = new TimerTask(this, INFINITE_LOOP, interval, onCallBack, args); AddTimer(timeTask); return timeTask; } public void AddTimer(TimerTask timerTask) { if (null != timerTask) { if (!timerTask.isFrameUpdate) { if (timerTask.interval <= 0) { timerTask.CallFunc(); return; } } timerTaskList.Add(timerTask); } } public void ClearAll() { timerTaskList.Clear(); timerTaskTriggers.Clear(); } public float GetTriggerTime(float interval) { return GetTime() + interval; } private void OnDestroy() { ClearAll(); timerTaskList = null; timerTaskTriggers = null; } } }