Unity延迟与异步操作方法详解

在Unity中处理延迟和异步操作时,常用以下三种方式:InvokeCoroutine 和 async/await。以下是它们的详细介绍、示例代码及使用场景对比。

一、Invoke(基于字符串的延迟调用)

特点:
  • 通过方法名的字符串调用,简单但类型不安全。

  • 支持单次延迟(Invoke)和重复调用(InvokeRepeating)。

  • 依赖 MonoBehaviour,停止时需调用 CancelInvoke

示例代码:
using UnityEngine;

public class InvokeExample : MonoBehaviour
{
    void Start()
    {
        // 单次延迟调用:2秒后执行SpawnEnemy
        Invoke("SpawnEnemy", 2f);

        // 重复调用:3秒后开始,每隔1秒执行一次Shoot
        InvokeRepeating("Shoot", 3f, 1f);
    }

    void SpawnEnemy() {
        Debug.Log("生成敌人!");
    }

    void Shoot() {
        Debug.Log("射击!");
    }

    void OnDisable() {
        // 停止所有Invoke调用
        CancelInvoke();
    }
}
缺点:
  • 字符串方法名易出错(如重命名方法后不会报错)。

  • 无法传递参数。


二、Coroutine(协程)

特点:
  • 基于 IEnumerator 和 yield,灵活控制执行流程。

  • 可暂停和恢复,适合复杂异步逻辑(如等待资源加载、动画完成)。

  • 通过 StartCoroutine 启动,StopCoroutine 停止。

示例代码:
using UnityEngine;
using System.Collections;

public class CoroutineExample : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(SpawnEnemyRoutine());
    }

    IEnumerator SpawnEnemyRoutine()
    {
        Debug.Log("协程开始");
        
        yield return new WaitForSeconds(2f); // 等待2秒
        SpawnEnemy();

        yield return new WaitForSeconds(1f); // 再等待1秒
        Debug.Log("继续执行");

        // 循环生成敌人,每3秒一次
        while (true)
        {
            SpawnEnemy();
            yield return new WaitForSeconds(3f);
        }
    }

    void SpawnEnemy() {
        Debug.Log("生成敌人!");
    }

    void OnDisable() {
        StopAllCoroutines(); // 停止所有协程
    }
}
进阶用法:
  • yield return new WaitUntil(() => condition);:等待条件满足。

  • yield return StartCoroutine(OtherRoutine());:嵌套协程。


三、async/await(C#原生异步)

特点:
  • 语法简洁,类似同步代码的异步操作。

  • 需Unity 2017+,推荐使用 UniTask 库优化性能。

  • 注意线程安全:Unity API需在主线程调用。

示例代码:
using UnityEngine;
using System.Threading.Tasks;

public class AsyncExample : MonoBehaviour
{
    async void Start()
    {
        Debug.Log("异步开始");
        
        await Task.Delay(2000); // 等待2秒(单位:毫秒)
        SpawnEnemy();

        await LoadResourceAsync(); // 等待资源加载
        Debug.Log("资源加载完成");
    }

    async Task LoadResourceAsync()
    {
        // 模拟异步加载(如AssetBundle)
        await Task.Delay(1000);
        Debug.Log("资源加载完毕");
    }

    void SpawnEnemy() {
        Debug.Log("生成敌人!");
    }
}
线程安全操作:
async void Start()
{
    // 在后台线程执行耗时计算
    int result = await Task.Run(() => HeavyCalculation());

    // 返回主线程更新UI
    await Task.Yield(); // 或使用 UniTask的SwitchToMainThread()
    Debug.Log("计算结果:" + result);
}

int HeavyCalculation() {
    // 模拟耗时计算
    return 42;
}

四、对比与使用场景

方式优点缺点适用场景
Invoke简单易用类型不安全、无法传参简单延迟(如3秒后销毁对象)
Coroutine灵活、支持复杂流程控制代码稍显冗长动画序列、分阶段任务
async/await现代语法、易处理复杂异步逻辑需注意线程安全(Unity API)网络请求、文件IO操作
最佳实践:
  1. 简单延迟:优先用 Invoke 或 Coroutine

  2. 复杂异步(如网络请求):优先用 async/await

  3. 循环任务Coroutine 的 while 循环更直观。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

☆平常心☆

若恰好帮到你,便是一场缘分

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值