using System.Collections.Generic; using System.Collections; using UnityEngine; namespace FairyGUI { public delegate void TimerCallback(object param); /// <summary> /// /// </summary> public class Timers { public static int repeat; public static float time; public static bool catchCallbackExceptions = false; Dictionary<TimerCallback, Anymous_T> _items; Dictionary<TimerCallback, Anymous_T> _toAdd; List<Anymous_T> _toRemove; List<Anymous_T> _pool; TimersEngine _engine; GameObject gameObject; private static Timers _inst; public static Timers inst { get { if (_inst == null) _inst = new Timers(); return _inst; } } public Timers() { _inst = this; gameObject = new GameObject("[FairyGUI.Timers]"); gameObject.hideFlags = HideFlags.HideInHierarchy; gameObject.SetActive(true); Object.DontDestroyOnLoad(gameObject); _engine = gameObject.AddComponent<TimersEngine>(); _items = new Dictionary<TimerCallback, Anymous_T>(); _toAdd = new Dictionary<TimerCallback, Anymous_T>(); _toRemove = new List<Anymous_T>(); _pool = new List<Anymous_T>(100); } public void Add(float interval, int repeat, TimerCallback callback) { Add(interval, repeat, callback, null); } /** * @interval in seconds * @repeat 0 indicate loop infinitely, otherwise the run count **/ public void Add(float interval, int repeat, TimerCallback callback, object callbackParam) { if (callback == null) { Debug.LogWarning("timer callback is null, " + interval + "," + repeat); return; } Anymous_T t; if (_items.TryGetValue(callback, out t)) { t.set(interval, repeat, callback, callbackParam); t.elapsed = 0; t.deleted = false; return; } if (_toAdd.TryGetValue(callback, out t)) { t.set(interval, repeat, callback, callbackParam); return; } t = GetFromPool(); t.interval = interval; t.repeat = repeat; t.callback = callback; t.param = callbackParam; _toAdd[callback] = t; } public void CallLater(TimerCallback callback) { Add(0.001f, 1, callback); } public void CallLater(TimerCallback callback, object callbackParam) { Add(0.001f, 1, callback, callbackParam); } public void AddUpdate(TimerCallback callback) { Add(0.001f, 0, callback); } public void AddUpdate(TimerCallback callback, object callbackParam) { Add(0.001f, 0, callback, callbackParam); } public void StartCoroutine(IEnumerator routine) { _engine.StartCoroutine(routine); } public bool Exists(TimerCallback callback) { if (_toAdd.ContainsKey(callback)) return true; Anymous_T at; if (_items.TryGetValue(callback, out at)) return !at.deleted; return false; } public void Remove(TimerCallback callback) { Anymous_T t; if (_toAdd.TryGetValue(callback, out t)) { _toAdd.Remove(callback); ReturnToPool(t); } if (_items.TryGetValue(callback, out t)) t.deleted = true; } private Anymous_T GetFromPool() { Anymous_T t; int cnt = _pool.Count; if (cnt > 0) { t = _pool[cnt - 1]; _pool.RemoveAt(cnt - 1); t.deleted = false; t.elapsed = 0; } else t = new Anymous_T(); return t; } private void ReturnToPool(Anymous_T t) { t.callback = null; _pool.Add(t); } public void Update() { float dt = Time.unscaledDeltaTime; Dictionary<TimerCallback, Anymous_T>.Enumerator iter; if (_items.Count > 0) { iter = _items.GetEnumerator(); while (iter.MoveNext()) { Anymous_T i = iter.Current.Value; if (i.deleted) { _toRemove.Add(i); continue; } i.elapsed += dt; if (i.elapsed < i.interval) continue; i.elapsed -= i.interval; if (i.elapsed < 0 || i.elapsed > 0.03f) i.elapsed = 0; if (i.repeat > 0) { i.repeat--; if (i.repeat == 0) { i.deleted = true; _toRemove.Add(i); } } repeat = i.repeat; if (i.callback != null) { if (catchCallbackExceptions) { try { i.callback(i.param); } catch (System.Exception e) { i.deleted = true; Debug.LogWarning("FairyGUI: timer(internal=" + i.interval + ", repeat=" + i.repeat + ") callback error > " + e.Message); } } else i.callback(i.param); } } iter.Dispose(); } int len = _toRemove.Count; if (len > 0) { for (int k = 0; k < len; k++) { Anymous_T i = _toRemove[k]; if (i.deleted && i.callback != null) { _items.Remove(i.callback); ReturnToPool(i); } } _toRemove.Clear(); } if (_toAdd.Count > 0) { iter = _toAdd.GetEnumerator(); while (iter.MoveNext()) _items.Add(iter.Current.Key, iter.Current.Value); iter.Dispose(); _toAdd.Clear(); } } } class Anymous_T { public float interval; public int repeat; public TimerCallback callback; public object param; public float elapsed; public bool deleted; public void set(float interval, int repeat, TimerCallback callback, object param) { this.interval = interval; this.repeat = repeat; this.callback = callback; this.param = param; } } class TimersEngine : MonoBehaviour { void Update() { Timers.inst.Update(); } } }