Unity 协程 Unity Task UniTask

协程在Unity中用于暂停执行,如WaitForSeconds用于延迟。WaitForSecondsRealtime不受时间缩放影响。WaitForEndOfFrame在帧渲染后执行。UnityTask的Task.Run更灵活,可在单独线程执行任务。协程必须依赖于Monobehaviour,而Task提供更多灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

协程

使用 StartCoroutine 和 IEnumerator
yield return null 暂停执行并随后在下一帧恢复
yield return new WaitForSeconds(1f); 延迟1秒
waitfor系列有好几个
在这里插入图片描述
WaitForSeconds 和 WaitForSecondsRealtime 的区别

使用缩放时间将协程执行暂停指定的秒数。

实际暂停时间等于给定时间除以 Time.timeScale。如果要使用未缩放时间进行等待,请参阅 WaitForSecondsRealtime。在协程中,WaitForSeconds 只能与 yield 语句结合使用。

有一些因素可能意味着实际等待的时间量与指定的时间量不完全一致。
1 在当前帧的 end 处开始等待。如果您在一个非常长的帧(例如,具有同步加载等阻止主线程的长时间操作的帧)上使用持续时间“t”启动 WaitForSeconds,协程将在帧结束后返回“t”秒,而不是取消后“t”秒。
2 允许协程在“t”秒后继续在第一帧上执行,不是确切的“t”秒之后。

WaitForEndOfFrame
等待,直到该帧结束,在 Unity 渲染每一个摄像机和 GUI 之后,在屏幕上显示该帧之前。

可以用它将显示内容读取到纹理中,将其编码为图像文件(请参阅 Texture2D.ReadPixels 和 Texture2D.Texture2D),并将其存储在设备上。
从 Game 视图切换到 Scene 视图将导致 WaitForEndOfFrame 冻结。它只在应用程序切换回 Game 视图时才会继续。只有当应用程序在 Unity 编辑器中运行时才会发生这种情况。

注意:在批处理模式下,不会在编辑器上调用此协程。如需了解更多详细信息,请参阅手册中的命令行参数页面。

WaitWhile 直到提供的委托评估为 false
WaitUntil 直到提供的委托评估为 true

注意:可以使用 StopCoroutine 和 StopAllCoroutines 来停止协程。 当用 SetActive(false) 禁用某个协程所附加到的游戏对象时,该协程也将停止。调用 Destroy(example)(其中 example 是一个 MonoBehaviour 实例)会立即触发 OnDisable,并会处理协程,从而有效地停止协程。最后,在帧的末尾调用 OnDestroy。

通过在 MonoBehaviour 实例上将 enabled 设置为 false 来禁用 MonoBehaviour 时,协程不会停止。

协程的缺点就是
他必须依赖 Monobehavior

Unity Task

相比 协程 Unity 的 Task 更加灵活

看例子

void Start()
{ 
     Debug.Log("1 : " + Thread.CurrentThread.ManagedThreadId);
     this.aaa();
     Debug.Log("2 : " + Thread.CurrentThread.ManagedThreadId);
}

async void aaa()
{
    Debug.Log("3 : " + Thread.CurrentThread.ManagedThreadId);
    await Task.Run(() =>
    {
        Debug.Log("5 : " + Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(3000);
        Debug.Log("6 : " + Thread.CurrentThread.ManagedThreadId);
    });
    Debug.Log("4 : " + Thread.CurrentThread.ManagedThreadId);
}

你会发现 Task.Run 里面的内容是单独id 也就是 5 和 6
其他所有的都是主线程id

### 协程返回值的处理方法 在 Unity 中,协程本身并不支持直接返回值。这是因为 `IEnumerator` 是一种迭代器模式实现,其设计初衷并不是为了传递数据回调,而是控制流程的暂停和恢复。然而,可以通过一些技巧来间接获取协程中的计算结果。 #### 方法一:使用类成员变量存储结果 通过将结果保存在一个共享的类成员变量中,外部代码可以在协程完成后读取该变量的内容。 ```csharp private float result; IEnumerator CalculateValue() { yield return new WaitForSeconds(1f); result = 42; // 假设这是我们要返回的结果 } void Start() { StartCoroutine(CalculateValue()); Invoke("UseResult", 1.1f); // 确保在协程结束后再访问result } void UseResult() { Debug.Log($"The calculated value is: {result}"); // 输出结果 } ``` 这种方法简单易懂,但需要注意时间上的同步问题[^1]。 #### 方法二:利用回调函数 另一种更灵活的方式是传入一个回调委托,在协程结束时调用此回调并将结果作为参数传递过去。 ```csharp public delegate void OnComplete(float value); IEnumerator CalculateWithCallback(OnComplete callback) { yield return new WaitForSeconds(1f); float computedValue = 42; if (callback != null) { callback(computedValue); // 调用回调并附带结果 } } void Start() { StartCoroutine(CalculateWithCallback((value) => { Debug.Log($"Received from coroutine: {value}"); })); } ``` 这种方式不仅提高了可维护性和扩展性,还避免了硬编码延迟带来的潜在风险[^2]。 #### 方法三:借助Task或async/await(需额外库) 如果项目允许引入第三方插件或者.NET标准版本较高,则可以考虑采用现代化异步编程模型——即基于Tasks的任务式API或者是完全原生的支持C#7以后特性下的async-await语法糖封装后的解决方案。不过这通常涉及到更多复杂度以及兼容性的考量[^3]。 例如下面展示了一个可能实现: ```csharp using System.Threading.Tasks; // 需要安装 UniTask 插件才能正常使用此类功能 public async Task<float> AsyncCalculateValueAsync() { await UniTask.Delay(TimeSpan.FromSeconds(1)); return 42; } void ExampleUsage() { var task = AsyncCalculateValueAsync(); task.ContinueWith(t => { Debug.Log($"Got the answer via Tasks API:{t.Result}"); }); } ``` 注意这里使用的UniTask来自Asset Store上免费提供的包,它提供了更好的性能表现同时也简化了很多传统写法下难以解决的问题比如主线程约束等等[^4]。 --- ### 总结 尽管Unity的标准协程机制不提供显式的return语句形式来回送数值,但是上述几种替代方案均能有效达成目的。开发者应依据具体应用场景和个人偏好选取最合适的策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值