Unity制作一个定时器Timer
Timer和TimerManager代码
using System.Collections; using UnityEngine; public class Timer : MonoBehaviour { public delegate void Notifier(); public Notifier onTimer; public Notifier onTimerReset; public Notifier onTimerComplete; public float interval; public int repeatCount = 0; public bool forever { get { return repeatCount == 0; } } public float time { get { if (running) { return crtCount * interval + Time.time - startTime; } return crtCount * interval + crtTime; } } protected float startTime; public int count { get { return crtCount; } } public bool complete { get { if (forever) { return false; } return crtCount == repeatCount; } } protected int crtCount = 0; protected float crtTime = 0f; public bool running = false; public void Dispose() { StopAllCoroutines(); ClearNotifiers(); } protected void OnDestroy() { ClearNotifiers(); } public void Reset() { if (running) { ClearCoroutine(); } crtCount = 0; crtTime = 0f; startTime = 0f; OnTimerReset(); } public void ResetPlay() { Play(0f); OnTimerReset(); } public void Stop() { if (running) { ClearCoroutine(); crtTime = Time.time - startTime; if (crtTime >= interval) { crtTime = interval - 0.00001f; } } } public void Play() { if (!running) { Play(time); } } public void Play(float offset) { if (running) { ClearCoroutine(); } if (offset < 0) { offset = 0; } else if (offset > 0 && !forever) { float totalTime = interval * repeatCount; if (offset > totalTime) { offset = totalTime; } } crtCount = Mathf.FloorToInt(offset / interval); crtTime = offset % interval; startTime = Time.time - crtTime; if (crtCount < repeatCount || forever) { StartCoroutine(Run()); running = true; } } private IEnumerator Run() { while (true) { if (crtTime > 0) { yield return new WaitForSeconds(interval - crtTime); OnTimer(); crtTime = 0; } yield return new WaitForSeconds(interval); OnTimer(); } } private void OnTimer() { crtCount++; if (!forever && crtCount >= repeatCount) { ClearCoroutine(); } else { startTime = Time.time; } if (onTimer != null) { onTimer(); } if (onTimerComplete != null && !forever && crtCount >= repeatCount) { onTimerComplete(); } } private void OnTimerReset() { if (onTimerReset != null) { onTimerReset(); } } public void ClearNotifiers() { onTimer = null; onTimerComplete = null; onTimerReset = null; } private void ClearCoroutine() { StopAllCoroutines(); running = false; } }
using System.Collections.Generic; using UnityEngine; public class TimerManager : MonoBehaviour { private const string MonoSingleName = "TimerManager"; private static GameObject monoSingle; private static TimerManager instance; private bool destroyed { get; set; } public static bool HasInstance { get { return instance != null; } } public static TimerManager InitInstance() { return Instance; } public static TimerManager Instance { get { if (monoSingle == null) { monoSingle = GameObject.Find(MonoSingleName); if (monoSingle == null) { monoSingle = new GameObject(); monoSingle.name = MonoSingleName; //monoSingle.transform.SetParent(Core.Instance.transform); } } if (instance == null) { instance = monoSingle.GetComponent<TimerManager>(); if (instance == null) { instance = monoSingle.AddComponent<TimerManager>(); } if (monoSingle.transform.parent == null) { DontDestroyOnLoad(monoSingle); } } return instance; } } private GameObject timerGO; private List<Timer> freeTimers; protected void Awake() { timerGO = new GameObject(); timerGO.name = "TimerCpts"; timerGO.transform.SetParent(monoSingle.transform); freeTimers = new List<Timer>(); } internal void Dispose() { if (timerGO != null) { Timer[] timers = timerGO.GetComponents<Timer>(); for (int i = 0; i < timers.Length; i++) { timers[i].Dispose(); } GameObject.Destroy(timerGO); timerGO = null; } freeTimers = null; } protected void OnDestroy() { if (!destroyed) { Dispose(); } } /// <summary> /// 创建一个定时器 /// </summary> /// <param name="interval">每N秒触发一次onTimer事件</param> /// <param name="repeatCount">一总触发多少次onTimer,所有出发完成后会自动删除,如果为0,forever</param> /// <returns></returns> private Timer CreateTimer(float interval, int repeatCount) { Timer timer = timerGO.AddComponent<Timer>(); timer.interval = interval; timer.repeatCount = repeatCount; return timer; } /// <summary> /// 临时租用 /// </summary> /// <param name="interval">间隔</param> /// <param name="repeatCount">最多触发次数如果为0,表示forever</param> /// <returns></returns> public Timer BorrowTimer(float interval, int repeatCount) { Timer timer; if (freeTimers.Count > 0) { timer = freeTimers[0]; freeTimers.RemoveAt(0); timer.enabled = true; timer.interval = interval; timer.repeatCount = repeatCount; } else { timer = CreateTimer(interval, repeatCount); } return timer; } /// <summary> /// 归还,备下次用 /// </summary> /// <param name="timer"></param> public void ReturnTimer(Timer timer) { if (destroyed) return; if (freeTimers.IndexOf(timer) != -1) { Debug.LogError("TimeMgr.ReturnTimer:freeTimers.IndexOf(timer) != -1,退还逻辑出错,请检查逻辑,同一个Timer被多次退还"); return; } timer.Stop(); timer.ClearNotifiers(); timer.Reset(); timer.enabled = false; freeTimers.Add(timer); } }
测试用法:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { private Timer timer; void Start() { if (timer==null) { timer = TimerManager.Instance.BorrowTimer(3,5); timer.onTimer += Print; timer.Play(); } } private void Print() { Debug.Log(Time.time); } // Update is called once per frame void Update() { } }