目錄
一、Mono中的延時函數Invoke
1. Invoke作用:延遲指定時間后執行一次函數。API:
2. InvokeRepeating作用:延遲后開始重復執行函數。API:
3. CancelInvoke作用:停止所有延時函數,或停止指定函數的延時執行。API:
4. IsInvoking作用:檢查是否有延時函數正在運行。API:
二、?Update 循環 + 計時器實現延時
三、異步 async/await(需 .NET 4.x+)
一、Mono中的延時函數Invoke
1. Invoke
作用:延遲指定時間后執行一次函數。
API:
void Invoke(string methodName, float time);
methodName:要執行的函數名(字符串形式)。
time:延遲時間(秒)
示例:
void Start()
{// 3秒后執行 Shoot 函數Invoke("Shoot", 3f);
}void Shoot()
{Debug.Log("發射子彈!");
}
注意事項:
函數名必須為字符串且嚴格匹配。
無法直接傳遞參數,需通過成員變量間接實現。
2. InvokeRepeating
作用:延遲后開始重復執行函數。
API:
void InvokeRepeating(string methodName, float delay, float repeatRate);
methodName:函數名(字符串)。
delay:第一次執行的延遲時間。
repeatRate:后續每次執行的間隔時間。
void Start()
{// 延遲2秒后,每隔1秒生成一個敵人InvokeRepeating("SpawnEnemy", 2f, 1f);
}void SpawnEnemy()
{Debug.Log("敵人生成!");
}
注意:若需停止重復執行,需手動調用 CancelInvoke。?
3. CancelInvoke
作用:停止所有延時函數,或停止指定函數的延時執行。
API:
void CancelInvoke(); ? ? ? ? ? ? ?// 停止所有延時函數
void CancelInvoke(string methodName); // 停止指定函數名的延時
void Update()
{if (Input.GetKeyDown(KeyCode.Space)){// 停止所有延時函數CancelInvoke();// 或僅停止 SpawnEnemy 的延時CancelInvoke("SpawnEnemy");}
}
即使函數未在運行,調用 CancelInvoke 也不會報錯。?
4. IsInvoking
作用:檢查是否有延時函數正在運行。
API:
bool IsInvoking(); ? ? ? ? ? ? ?// 檢查是否有任何延時函數在執行
bool IsInvoking(string methodName); // 檢查指定函數是否在延時執行中
void Update()
{if (IsInvoking("SpawnEnemy")){Debug.Log("正在生成敵人...");}
}
關鍵特性與注意事項
對象狀態影響:
腳本或對象失活(SetActive(false))時,延時函數仍會執行。
對象被銷毀(Destroy)或腳本被移除時,延時函數自動終止。
函數要求:
必須為本腳本中聲明的無參函數。
函數名需完全匹配(區分大小寫)。
參數傳遞限制:
無法直接傳參,可通過類成員變量間接實現:
private int _bulletType;void Start()
{_bulletType = 2;Invoke("Shoot", 1f);
}void Shoot()
{Debug.Log("發射類型為 " + _bulletType + " 的子彈");
}
二、?Update 循環 + 計時器實現延時
原理:在 Update 中通過累加 Time.deltaTime 手動控制計時器,觸發目標函數。
優點:靈活性高,可中途修改延遲時間或邏輯。
缺點:需自行管理計時器,代碼量稍多。
using UnityEngine;public class TimerExample : MonoBehaviour
{private float _delay = 2f;//延時時間private float _timer;//定時器private bool _hasTriggered;//是否處于延時間隔中void Update(){if (!_hasTriggered)//不處于延時間隔中{_timer += Time.deltaTime;//改變定時器 直到達到指定延時if (_timer >= _delay){DoSomething();_hasTriggered = true;}}}void DoSomething(){Debug.Log("2秒后執行!");}
}
例如實現一個可重復計時的定時器:
using UnityEngine;
using System;/// <summary>
/// 可重復觸發的定時器(基于游戲時間)
/// </summary>
public class GameTimer
{// 定時器觸發事件public event Action OnTimerTriggered;private float _interval; // 觸發間隔(秒)private float _nextTriggerTime; // 下次觸發時間private bool _isActive; // 定時器是否激活private bool _isRepeating; // 是否重復觸發/// <summary>/// 初始化定時器/// </summary>/// <param name="interval">觸發間隔(秒)</param>/// <param name="isRepeating">是否重復</param>public GameTimer(float interval, bool isRepeating){_interval = interval;_isRepeating = isRepeating;}/// <summary>/// 啟動/重啟定時器/// </summary>public void Start(){_isActive = true;_nextTriggerTime = Time.time + _interval;}/// <summary>/// 停止定時器/// </summary>public void Stop(){_isActive = false;}/// <summary>/// 每幀更新定時器狀態/// </summary>public void Update(){if (!_isActive || Time.time < _nextTriggerTime) return;// 觸發事件OnTimerTriggered?.Invoke();if (_isRepeating){// 更新下次觸發時間(避免誤差累積)_nextTriggerTime = Time.time + _interval;}else{Stop();}}
}
?測試:
using UnityEngine;public class TimerExample : MonoBehaviour
{private GameTimer _gameTimer;private FrameTimer _frameTimer;void Start(){// 創建每5秒觸發一次的重復定時器(精準時間)_gameTimer = new GameTimer(5f, true);_gameTimer.OnTimerTriggered += HandleGameTimer;_gameTimer.Start();// 創建每1秒觸發一次的重復定時器(幀累積)_frameTimer = new FrameTimer(1f, true);_frameTimer.OnTimerTriggered += HandleFrameTimer;_frameTimer.Start();}void Update(){_gameTimer.Update();_frameTimer.Update();}void HandleGameTimer(){Debug.Log($"精準定時器觸發,當前時間:{Time.time}");}void HandleFrameTimer(){Debug.Log($"幀累積定時器觸發,運行時間:{Time.time}");}void OnDestroy(){_gameTimer.Stop();_frameTimer.Stop();}
}
三、異步 async/await(需 .NET 4.x+)
? ? ? ? 這個是多線程的知識,主線程也是線程嘛,都可以直接作用。后面再詳細介紹關于Task類的知識,這里簡單了解即可。只需要知道 這樣子也可以延時,后面我們學了協同,那個也可以延時。
async 修飾符:標記方法為異步方法,允許內部使用 await。
await 關鍵字:暫停當前異步方法的執行,直到其等待的任務完成,期間釋放控制權給調用者。
原理:使用 C# 原生異步語法,通過 Task.Delay 實現延時。
優點:代碼簡潔,支持復雜異步邏輯。
缺點:需 Unity 2018+ 并啟用 .NET 4.x 運行時版本。
環境配置
Player Settings -> Configuration -> Scripting Runtime Version -> .NET 4.x Project Settings -> Player -> Api Compatibility Level -> .NET 4.x 新版本可能不叫這個名字選.NET Framwork也是一樣的
using UnityEngine;
using System.Threading.Tasks;public class AsyncAwaitExample : MonoBehaviour
{async void Start(){Debug.Log("開始等待...");await Task.Delay(2000); // 毫秒單位Debug.Log("2秒后執行!");// 注意:此處代碼仍在主線程執行}
}
注意事項
若需操作 Unity 對象(如 GameObject),需在主線程執行,避免使用 Task.Run。
與協程不同,async/await 不依賴 Unity 的生命周期,但需處理對象銷毀時的 Task 終止。?