Unity中协程的异常处理

2024-03-25

我创建了一个脚本来更改它所附加的游戏对象的透明度,并且我在需要可取消的淡入淡出协程中进行透明度更改(并且每次我们调用时都取消)ChangeTransparency()具有新的值)。我设法让它按照我想要的方式工作,但我想处理OperationCanceledException那淹没了我的控制台。我知道你cannot wrap a yield return里面的声明try-catch block.

处理 Unity 协程内异常的正确方法是什么?

这是我的脚本:

using System;
using System.Collections;
using System.Threading;
using UnityEngine;

public class Seethrough : MonoBehaviour
{
    private bool isTransparent = false;
    private Renderer componentRenderer;
    private CancellationTokenSource cts;
    private const string materialTransparencyProperty = "_Fade";


    private void Start()
    {
        cts = new CancellationTokenSource();

        componentRenderer = GetComponent<Renderer>();
    }

    public void ChangeTransparency(bool transparent)
    {
        //Avoid to set the same transparency twice
        if (this.isTransparent == transparent) return;

        //Set the new configuration
        this.isTransparent = transparent;

        cts?.Cancel();
        cts = new CancellationTokenSource();

        if (transparent)
        {
            StartCoroutine(FadeTransparency(0.4f, 0.6f, cts.Token));
        }
        else
        {
            StartCoroutine(FadeTransparency(1f, 0.5f, cts.Token));
        }
    }

    private IEnumerator FadeTransparency(float targetValue, float duration, CancellationToken token)
    {
        Material[] materials = componentRenderer.materials;
        foreach (Material material in materials)
        {
            float startValue = material.GetFloat(materialTransparencyProperty);
            float time = 0;

            while (time < duration)
            {
                token.ThrowIfCancellationRequested();  // I would like to handle this exception somehow while still canceling the coroutine

                material.SetFloat(materialTransparencyProperty, Mathf.Lerp(startValue, targetValue, time / duration));
                time += Time.deltaTime;
                yield return null;
            }

            material.SetFloat(materialTransparencyProperty, targetValue);
        }
    }
}

我的临时解决方案是检查令牌的取消标志并跳出 while 循环。虽然它解决了当前的问题,但我仍然需要一种方法来处理 Unity 中异步方法(协程)中引发的这些异常。


The 其他答案 https://stackoverflow.com/a/70358869/7111561很好,但实际上并不适合您要解决的用例。

您没有任何异步代码,但需要在 Unity 主线程中执行代码,因为它使用 Unity API 并且大部分代码只能在主线程上使用。

A 协程 https://docs.unity3d.com/Manual/Coroutines.html is 非异步与多线程或任务无关!

协程基本上只是一个IEnumerator一旦它被注册为协程StartCorotuine然后Unity调用MoveNext在它上面(这将执行一切,直到下一个yield return声明)之后Update所以一旦一帧(有一些特殊的yield语句,比如WaitForFixedUpdate等,它们在不同的消息堆栈中处理,但仍然在 Unity 主线程上处理。

So e.g.

// Tells Unity to "pause" the routine here, render this frame
// and continue from here in the next frame
yield return null;

or

// Will once a frame check if the provided time in seconds has already exceeded
// if so continues in the next frame, if not checks again in the next frame
yield return new WaitForSeconds(3f);

如果您确实需要以某种方式对例程本身内的取消做出反应,那么除了立即抛出异常而不是仅检查CancellationToken.IsCancellationRequested https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken.iscancellationrequested#System_Threading_CancellationToken_IsCancellationRequested并对其做出反应

while (time < duration)
{
    if(token.IsCancellationRequested)
    {
        // Handle the cancelation

        // exits the Coroutine / IEnumerator regardless of how deep it is nested in loops
        // not to confuse with only "break" which would only exit the while loop
        yield break;
    }
            
    ....

也回答你的标题。确实你做不到yield return里面一个try - catch阻止并且正如一般所说,无论如何都没有真正的理由这样做。

如果您确实需要,您可以包装代码的某些部分,而无需yield return in a try - catch块并在catch你做了你的错误处理,然后你就可以再次yield break.

private IEnumerator SomeRoutine()
{
    while(true)
    {
        try
        {
            if(Random.Range(0, 10) == 9) throw new Exception ("Plop!");
        }
        catch(Exception e)
        {
            Debug.LogException(e);
            yield break;
        }

        yield return null;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity中协程的异常处理 的相关文章

随机推荐

  • 解决方案构建顺序的保存位置

    我有一个包含多个项目 csproj 和 btproj 的解决方案 我实际上正在运行 BizTalk 2013 R2 因此我在 Visual Studio 2013 下进行开发 我有许多 powershell 脚本来部署我的应用程序 我必须增
  • 查找包含任意坐标列表的 voronoi 区域

    我正在使用一种算法 对于每次迭代 都需要找到一组任意坐标属于 Voronoi 图的哪个区域 即每个坐标位于哪个区域内 我们可以假设所有坐标都属于一个区域 如果这有什么区别的话 我还没有任何可以在 Python 中运行的代码 但伪代码如下所示
  • 将 OS National Grid 名称/代码添加到 R 中的网格

    我希望重新创建完整的地形测量国家网格 如此处所示https upload wikimedia org wikipedia commons f f5 Ordnance Survey National Grid svg https upload
  • 如何将工作表保存到新工作簿?

    我正在尝试将单个工作表保存到新工作簿 VBA 应该创建一个新工作簿 代码正在运行 新工作簿会弹出 其中包含所需的数据 并且 另存为 对话框窗口也会打开 但是当我选择名称并保存文件时 找不到新工作簿保持打开状态 Book1 或无论自动填充什么
  • 如何在Python中的recv之前找出socket中有多少字节?

    我有一个处理数据流的 TCP 它一次需要 4096 个字节 但我需要一种方法在接收之前找出整个套接字的大小 这样我就可以确定在切换套接字之前套接字将被读取多少次 它还会通知这是该套接字的最后一次接收 以便我可以在选择切换到另一个套接字 当它
  • SSL 启用:Windows 7 中的 Tomcat [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 当我尝试在 Windows 7 中启用 SSL 编辑 server xml 以启用端口 8443 作为 HTTPS 时 它没有被启用 有时它会显示 连
  • 列出两个日期之间的天数数组

    我想列出两个日期之间的一系列天数 我可以使用下面的代码列出一系列月份 我如何更改它以显示两个日期之间的每一天 require date date from Date parse 2011 05 14 date to Date parse 2
  • 自定义视图引擎中的 ASP.NET MVC 自定义属性

    假设我写了一个自定义属性 public class SpecialActionFilterAttribute System Web Mvc ActionFilterAttribute public override void OnActio
  • 如何将 grep 的输出通过管道传输到 cp?

    我有一个工作grep选择满足特定条件的文件的命令 我怎样才能从grep命令并将其通过管道传输到cp命令 以下尝试都失败了cp end grep r TWL exclude csv cp data lidar tmp ajp2 cp 之后缺少
  • 用于 SSO 的 PHP + ADFS(通过 OAuth) - 如何设置 ADFS?

    我正在尝试使用ADFS for SSO在一个项目上 该项目正在进行中PHP我正在尝试使用OAuth为了这 那么设置 ADFS 以与 OAuth2 配合使用的步骤是什么 我对 ADFS 一无所知 也无法在那里获得有关 OAuth2 设置的任何
  • 使用 -static-libgcc 和 -static-libstdc++ 编译 libconfig++

    我正在尝试编译库配置 http www hyperrealm com libconfig 版本 1 4 8 与 make LDFLAGS static libstdc static libgcc 但这似乎不起作用 因为我仍然得到 reade
  • 无法使用 Gradle 运行 TestNG

    我有一个使用 TestNG 运行的简单代码 但我无法使用 Gradle 运行相同的代码 因为它说找不到 main 方法 这并不奇怪 因为我使用的是注释 但在这样的场景下 如果我必须使用Gradle 如何运行代码 请注意 我对 Gradle
  • 如何根据 Django 中的表单输入向用户显示生成的图像?

    我目前正在使用对象的属性通过 matplotlib 生成图像 并且能够创建一个在 HttpResponse 中显示所述图像的视图 我使用以下代码片段来执行此操作 http wiki scipy org Cookbook Matplotlib
  • Pandas - KeyError:列不在索引中[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 import pandas as pd import quandl df quandl get WIKI GOOGL p
  • 如何将 MKMapView 用户位置蓝点更改为所选图像?

    是否可以更改blue dot https i stack imgur com ELWID jpg这表明用户的位置MKMapView到图像 例如一辆小汽车或任何 png image In the 查看注释 的方法MKMapViewDelega
  • 循环引用时 .NET 单元测试中的 StackOverflow

    当我注意到以下情况时 我正在测试其他循环参考电阻 public class Foo private Bar myBar new Bar public class Bar private Foo myFoo new Foo Fact publ
  • “pointer-events: none”在 IE9 和 IE10 中不起作用

    CSS 属性pointer events none 在 Firefox 中工作正常 但在 Internet Explorer 9 10 中则不然 有没有办法在 IE 中实现该属性的相同行为 有任何想法吗 来自 MDN 文档 警告 在 CSS
  • React:检查器不是一个函数

    我在 React 应用程序的控制台中收到这条奇怪的警告消息 警告 Failed propType checker is not a function 检查渲染方法Chart 我根本没有任何检查方法 如果我删除我的propTypes 警告消失
  • 姜戈 1.5。 'url' 需要一个非空的第一个参数。 Django 1.5 中的语法发生了变化

    如果我尝试 href url post content product id p id 我有这个错误 url 需要一个非空的第一个参数 语法发生了变化 Django 1 5 请参阅文档 如何改变呢 Django 1 5 中的更改 第一个参数
  • Unity中协程的异常处理

    我创建了一个脚本来更改它所附加的游戏对象的透明度 并且我在需要可取消的淡入淡出协程中进行透明度更改 并且每次我们调用时都取消 ChangeTransparency 具有新的值 我设法让它按照我想要的方式工作 但我想处理OperationCa