Unity計時器(實現暫停,繼續等功能)
阿新 • • 發佈:2018-12-23
計時器是遊戲開發的一個非常常用的功能,簡單計時器的實現方式有很多中,可以每幀給一個float變數加Time.deltaTime,到一定時間的時候呼叫某個函式。也可以使用unity的協程和InvokeRepeating。但是簡單的使用這些組合呼叫起來不是很方便,並且無法實現暫停,繼續等功能,也無法在計時器執行到某個時間點的時候移除或者新增新的事件。
1.計時器
這個計時器用到了之前文章裡的Singleton和MonoEvent,連結在此 Unity單例模式及MonoEvent
直接上程式碼,註釋也很詳細,後面再寫上使用方式。一共兩個類,一個Timer是計時器,TimeManager由於只在Timer中用到,直接定義在Timer裡面。
using System.Collections; using System.Collections.Generic; using UnityEngine; using OnEventDelegate = System.Action; public class Timer { private OnEventDelegate timeUpDel; /// <summary> /// 是否執行 /// </summary> private bool _isRunning; /// <summary> /// 已執行時間(每次滿足執行間隔就會加這個) /// </summary> private float _useTime; /// <summary> /// 執行時間 /// </summary> public float RunTime { get; private set; } /// <summary> /// 已執行次數 /// </summary> public int UseCount { get; private set; } /// <summary> /// 執行間隔 /// </summary> public float TimeInterval { get; set; } /// <summary> /// 設定的執行次數 /// </summary> public int RepeatCount { get; set; } /// <summary> /// <param name="interval">時間間隔,單位是毫秒</param> /// <param name="repeatCount">執行次數,一秒一次的話MaxValue可以執行68年</param> /// </summary> public Timer(float interval, int repeatCount = int.MaxValue) { RunTime = 0f; TimeInterval = Mathf.Max(interval, 1); // 最小間隔為1毫秒 RepeatCount = repeatCount; } /// <summary> /// 是否執行中 /// </summary> public bool IsRunning { get { return _isRunning; } set { if (_isRunning != value) { _isRunning = value; if (_isRunning) { TimerManager.Instance.AddTimer(this); } else { TimerManager.Instance.RemoveTimer(this); } //這裡可以加一個計時器狀態變換的委託 } } } /// <summary> /// 每幀執行 /// </summary> /// <param name="deltaTime"></param> public void Update(float deltaTime) { if (IsRunning && UseCount < RepeatCount) { RunTime += deltaTime; var f = TimeInterval / 1000; while (RunTime - _useTime > f && UseCount < RepeatCount) { UseCount++; _useTime += f; timeUpDel?.Invoke(); } } if (UseCount >= RepeatCount) { IsRunning = false; } } /// <summary> /// 新增事件 /// </summary> /// <param name="type"></param> /// <param name="fun"></param> public void AddEventListener(OnEventDelegate fun) { timeUpDel += fun; } /// <summary> /// 移除事件 /// </summary> /// <param name="type"></param> /// <param name="fun"></param> public void RemoveEventListener(OnEventDelegate fun) { timeUpDel -= fun; } /// <summary> /// 開始(呼叫了IsRunning的Set,初始化了TimerManager) /// </summary> public void Start() { IsRunning = true; } /// <summary> /// 停止 /// </summary> public void Pause() { IsRunning = false; } /// <summary> /// 重置 /// </summary> public void ReSet() { IsRunning = false; RunTime = 0f; _useTime = 0f; UseCount = 0; } /// <summary> /// 計時器管理 /// 除了計時器以外其他類暫時不需要呼叫,以後需要再放到外面去 /// </summary> public class TimerManager : Singleton<TimerManager> { private readonly List<Timer> _timers = new List<Timer>(); public TimerManager() { MonoEvent.Instance.LATEUPDATE += LateUpdate; } private void LateUpdate() { for (var i = 0; i < _timers.Count; i++) { if (_timers[i].IsRunning) { // unscaledDeltaTime和deltaTime一樣,但是不受TimeScale影響 _timers[i].Update(Time.unscaledDeltaTime); } } } public void AddTimer(Timer timer) { if (_timers.Contains(timer) == false) { _timers.Add(timer); } } public void RemoveTimer(Timer timer) { if (_timers.Contains(timer)) { _timers.Remove(timer); } } } }
2.使用方式
步驟一:構造
Timer timer = new Timer(1000,3); // 計時器的構造以毫秒為單位,這是一個沒秒觸發一次,觸發三次結束的計時器
步驟二:新增事件
事件的新增和Button的onClick.AddListener()一樣,將函式當引數傳入,也可以使用Lambda表示式
timer.AddEventListener(() =>
{
Debug.Log("new time");
});對應的還有移除事件
timer.RemoveEventListener
步驟三:操作
timer.Start(); // 開始
timer.Pause(); // 暫停
timer.ReSet(); // 重置暫停後繼續計時器也呼叫timer.Start();