Unity基础学习(五)Mono中的重要内容(1)延时函数
目录
一、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 终止。