You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity C#异步值渐变函数特定场景下首次循环后停止运行问题

问题根因

这是C#中循环变量闭包捕获的经典问题:for循环的迭代变量i的作用域是整个循环体,你传入SetValueInTime的lambda表达式捕获的是变量i本身而非当前迭代的i值。当SetValueInTime内部第一次执行await Task.Yield()让出主线程后,for循环已经执行完毕,此时i的值已经变为1(满足i<1的退出条件),后续异步逻辑执行时访问glowGO[i]会触发索引越界异常。由于你没有await SetValueInTime返回的Task,异常会被吞在Task上下文内,不会直接抛出到主线程,就会表现为逻辑无响应。
你直接写死索引0的时候没有捕获迭代变量,自然不会触发这个问题。

解决方案

在循环内部声明局部变量存储当前迭代的i值,lambda捕获这个局部变量即可:

public Color startColor = Color.white;
public GameObject[] glowGO;
for(int i = 0; i< glowGO.Length; i++)
{
    // 新增局部变量,每个迭代都会生成独立的实例供lambda捕获
    int currentIndex = i;
    SetValueInTime(3, () => 10,
        () =>
        {
            MaterialPropertyBlock block = new MaterialPropertyBlock();
            glowGO[currentIndex].GetComponent<Renderer>().GetPropertyBlock(block);
            float intensity = Mathf.Log(block.GetVector("_Tint").x / startColor.r, 2);
            return intensity;
        }, (x) =>
        {
            MaterialPropertyBlock block = new MaterialPropertyBlock();
            var tempColor = startColor * Mathf.Pow(2, x);
            block.SetVector("_Tint", new Vector4(tempColor.r, tempColor.g, tempColor.b, 1));
            glowGO[currentIndex].GetComponent<Renderer>().SetPropertyBlock(block);

        }, glowToken.Token);
}

额外优化建议

  • 可以提前缓存所有Renderer引用,避免lambda中每次执行都调用GetComponent,减少性能开销
  • 建议添加对SetValueInTime返回Task的异常处理,避免静默失败排查困难
  • 可以调整SetValueInTime内部的判断顺序,优先判断cancellationToken.IsCancellationRequested,避免取消后仍执行多余的属性赋值逻辑

内容的提问来源于stack exchange,提问作者braniac ba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 18:54:06