【问题标题】:Unity | Coroutine Speeding Up After Each Executions团结 |每次执行后协程加速
【发布时间】:2019-08-26 11:06:49
【问题描述】:

我的协程在玩家死后淡出玩家,

// Fade out ragdoll
IEnumerator RagdollFade()
{
    yield return new WaitForSeconds(3f);

    while (startingColour.a > 0.0f)
    {
        headSR.color = new Color(headSR.color.r, headSR.color.g, headSR.color.b, headSR.color.a - (Time.deltaTime / 1.5f));
        bodySR.color = new Color(bodySR.color.r, bodySR.color.g, bodySR.color.b, bodySR.color.a - (Time.deltaTime / 1.5f));
        leftArmSR.color = new Color(leftArmSR.color.r, leftArmSR.color.g, leftArmSR.color.b, leftArmSR.color.a - (Time.deltaTime / 1.5f));
        rightArmSR.color = new Color(rightArmSR.color.r, rightArmSR.color.g, rightArmSR.color.b, rightArmSR.color.a - (Time.deltaTime / 1.5f));
        leftLegSR.color = new Color(leftLegSR.color.r, leftLegSR.color.g, leftLegSR.color.b, leftLegSR.color.a - (Time.deltaTime / 1.5f));
        rightLegSR.color = new Color(rightLegSR.color.r, rightLegSR.color.g, rightLegSR.color.b, rightLegSR.color.a - (Time.deltaTime / 1.5f));

        yield return null;
    }
}

每次执行后都会加快速度。

例如,第一次调用协程时一切正常,3 秒后播放器淡出。但是,下一次它被称为 3 秒在淡入淡出之前不要过去,下一次更短的时间等等。

startingColour 在 Start() 函数中设置。

【问题讨论】:

  • 你永远不会修改startingColour.a,所以你永远不会离开while循环?
  • @LudovicFeltz 措辞不佳,我确实改变了它 - 起始值在 start 函数中设置
  • 你确定要离开while循环吗?
  • 它应该做什么? startingColour.a 是否在其他任何地方更改?否则你不能简单地使用while(true)吗? headSR.color 等在哪里重置?我的意思是,一旦您将它们淡出.. 停留会淡出吗?在这种情况下,第二次更快并不奇怪。正如@LudovicFeltz 所说,您可能永远不会离开 while 循环?因此,当您再次调用 StartCoroutine 时,您将运行两个并发例程
  • @derHugo 基本上,当玩家死亡时,我希望他们的身体消失。因为它们是布娃娃,所以我必须淡出每个部分(即头部、身体等)。 while true 是一种更简单的写法,我的错。我曾尝试在此协程结束时和调用之前重置headSR.color,但没有任何变化。 headSR.color = startingColour;

标签: c# unity3d coroutine


【解决方案1】:

您的startingColour.a 值似乎总是大于0,因此while 循环永远不会结束,您的协程只会永远运行。如果不查看其余代码,很难判断。

所以如果你第二次启动它,你现在有两个例程并行运行 => 现在每一帧你将 alphas 减少两倍..然后三倍..等等,它也不会等待 3 秒之前第一个调用的例程已经在运行 while 循环,因此它们会继续降低 alpha。


您可以使用StopAllCoroutinesStopCoroutine 在开始新的例程时中断任何仍在运行的例程。但这实际上更像是一种肮脏的解决方法。


我宁愿解决实际问题并确保您的 while 循环返回,这目前不太可能发生,因为您似乎没有在任何地方更改 startColor.a

或者添加一个不允许并行例程的标志,例如

private bool isFading;

IEnumerator RagdollFade()
{
    if(isFading) yield brake;

    // prevents other routines
    isFading = true;

    ...

    // reset the flag once routine is finished
    isFading = false;
}

那么我还建议使用一个 float 值,用于使用 Color.Lerp 之类的褪色

private bool isFading;

// you can also use a fixed duration and not pass it as parameter
// but this way you are even more flexible
IEnumerator RagdollFade(float duration)
{
    if(isFading) yield brake;

    // prevents other routines
    isFading = true;

    yield return new WaitForSeconds(3f);

    // it is more performant to gather all required information beforehand

    headStartColor = headSR.color;
    bodyStartColor = bodySR.color;
    leftArmStartColor = leftArmSR.color;
    rightArmStartColor = rightArmSR.color;
    leftLegStartColor = leftLegSR.color;
    rightLegStartColor = rightLegSR.color;

    headTargetColor = new Color(headStartColor.r, headStartColor.g, headStartColor.b, 0f);
    bodyTargetColor = new Color(bodyStartColor.r, bodyStartColor.g, bodyStartColor.b, 0f);
    leftArmTargetColor = new Color(leftArmStartColor.r, leftArmStartColor.g, leftArmStartColor.b, 0f);
    rightArmTargetColor = new Color(rightArmStartColor.r, rightArmStartColor.g, rightArmStartColor.b, 0f);
    leftLegTargetColor = new Color(leftLegStartColor.r, leftLegStartColor.g, leftLegStartColor.b, 0f);
    rightLegTargetColor = new Color(rightLegStartColor.r, rightLegStartColor.g, rightLegStartColor.b, 0f);

    var passedTime = 0f;
    while (passedTime < duration)
    {
        // get the interpolation factor from 0 to 1
        var factor = passedTime / duration;
        // for adding additional ease-in and ease-out
        // factor = Mathf.SmoothStep(0, 1, factor);

        headSR.color = Color.Lerp(headStartColor, headTargetColor, factor);
        bodySR.color = Color.Lerp(bodyStartColor, bodyTargetColor, factor);
        leftArmSR.color = Color.Lerp(leftArmStartColor, leftArmTargetColor, factor);
        rightArmSR.color = Color.Lerp(rightArmStartColor, rightArmTargetColor, factor);
        leftLegSR.color = Color.Lerp(leftLegStartColor, leftLegTargetColor, factor);
        rightLegSR.color = Color.Lerp(rightLegStartColor, rightLegTargetColor, factor);


        // avoid overshooting
        passedTime += Mathf.Min(Time.deltatime, duration - passedTime);
        yield return null;
    }

    // reset the flag once routine is finished
    isFading = false;
}

这更加灵活,您可以使用任何您喜欢的简单数学来添加缓入和缓出。

【讨论】:

  • 哇,谢谢伙计!非常感谢您抽出宝贵的时间来写这篇文章,我会看看并在未来包含此类内容。感谢您的帮助:)。
  • 那你介意接受我的回答吗?如前所述,您接受的方法更像是一种肮脏的解决方法..并且是在我的帖子之后添加的;)
  • 哈哈,你得了 17.6k 分——我敢肯定,一滴滴不会痛。取而代之的是我目前看不见的赞成票:D。再次感谢,祝您有美好的一天:)。
  • @derHugo 完全同意 Wzrd。你的回答太棒了,但让我们也给新人一个机会:)
  • @GauravMall 我同意你们俩都支持新人.. 但在正确的条件下;)另一个帖子的质量是......好吧..
【解决方案2】:

在开始一个新的协程之前尝试调用StopCoroutine()。可能你有几个协同程序同时工作。

【讨论】:

  • 是的,就是这样,两个协程相互干扰。非常感谢。
【解决方案3】:

好的,我已经解决了问题,这完全是我的错。

我意识到我拥有的 ANOTHER 协程干扰了当前协程,这就是为什么 StopCoroutine() 和添加淡入淡出检查不起作用的原因。

抱歉,伙计们没有在我的问题帖子中包含这些内容,您可能能够更有效地帮助我。

所以对于以后遇到奇怪的例程行为的人,请确保两个协程之间没有相互干扰。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多