目录
1. Invoke作用:延迟指定时间后执行一次函数。API:
2. InvokeRepeating作用:延迟后开始重复执行函数。API:
3. CancelInvoke作用:停止所有延时函数,或停止指定函数的延时执行。API:
4. IsInvoking作用:检查是否有延时函数正在运行。API:
一、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 终止。