【问题标题】:Overriding coroutines not working as expected覆盖协程未按预期工作
【发布时间】:2021-09-09 23:59:27
【问题描述】:
protected virtual IEnumerator Lerp()
    {
        Debug.Log("BaseMethod");

        while (true)
        {
            speed = startSpeed;
            currentColor = SpriteRend.color;
            float r = Random.Range(0f, 1f),
                g = Random.Range(0f, 1f),
                b = Random.Range(0f, 1f),
                a = Random.Range(0f, 1f);
            nextColor = new Color(r, g, b, a);

            while (nextColor != (currentColor = Color.Lerp(currentColor, nextColor, speed * Time.deltaTime)))
            {

                if (AnyRgbValueReached())
                {
                    speed += 2f;
                }

                SpriteRend.color = currentColor;
                yield return null;
            }
        }
    }



protected override IEnumerator Lerp()
    {
        if (IsFirst)
        {
            while (!Game.GameInstance.GameOver)
            {
                if (Recording)
                {
                    Debug.Log("SubMethod");
                    yield return base.Lerp();                                                
                }
                else
                {
                    yield return null;

                }
            }
        }
        else
        {
            yield return new WaitForEndOfFrame();

            while (!Game.GameInstance.GameOver)
            {
                SpriteRend.color = firstTop.GetComponent<SpriteRenderer>().color;
                yield return null;
            }
        }
    }

注意:这 2 个方法不在 1 个类中,它们在 2 个单独的类中。

问题在于 Debug.Log("BaseMethod"); Debug.Log("SubMethod"); 时不打印正在打印每一帧。为什么会这样?

【问题讨论】:

  • 请将您的代码(的相关部分)复制到您的问题中,除非您可以保证链接的页面将至少在此问题存在期间可用可在线访问。否则,如果您的链接在未来某个时候失效,您的问题可能对未来的访问者毫无用处。

标签: c# unity3d


【解决方案1】:
 protected override IEnumerator Lerp()
 {
     if (IsFirst)
     {
         while (!Game.GameInstance.GameOver)
         {
             if (Recording)
             {
                 Debug.Log("SubMethod");
                 yield return StartCoroutin(base.Lerp());    // See here                                             
             }
             else
             {
                 yield return null;

             }
         }
     }
    // Rest of code
 }

这是一个协程,所以应该像一个协程一样调用它。

【讨论】:

  • 请注意,如果你这样做,当前的协程将不会继续,直到新的协程完成。所以你也可以试试 ' IEnumerator baseLerp = base.Lerp(); while (baseLerp.MoveNext()) { yield return null; }' 希望能帮助到你! :) 如果有不明白的地方请告诉我。
  • 这段代码有一个讨厌的副作用,就是启动一个新的协程,而不是在调用者的调用栈中继续。如果在返回 IEnumerator 的公共函数中使用此习惯用法,那么它可能会导致生成协程,其执行由与调用 StartCoroutine() 的原始对象完全不同的对象管理,这可能导致各种令人讨厌的事情,包括崩溃这发生在许多帧之后,然后是导致它们的原始函数调用和不同的对象。
【解决方案2】:

完成同样事情的更好方法是 (IMO) 执行我在下面概述的操作。

这消除了启动单独协程的非常讨厌的副作用 - 并且可能在与调用 StartCoroutine() 的原始单行为不同的 Monobehaviour 上。

它还有一个优点是,如果需要,您可以使用相同的方法无限期地嵌套额外的 IEnumerators(或多或少)。

public class BaseClass : MonoBehaviour
{
    // you'd normally start this using StartCoroutine( ... )
    public IEnumerator Lerp( /*params*/ )
    {
        // this is (approx.) how monobehaviour internally manages the coroutines you start with StartCoroutine()
        IEnumerator cInternalCoroutine = VInternalCoroutine( /*params*/ );

        // each call to MoveNext() progresses the IEnumerator to the next yield 
        // or end of the function if cInternalCoroutine.MoveNext() reaches the 
        // end of the function, or it returns "yield break" MoveNext() returns false 
        // & the loop ends
        while( cInternalCoroutine.MoveNext() )
        {
            yield return cInternalCoroutine.Current;
        }
    }

    protected virtual IEnumerator VInternalCoroutine( /*params*/ )
    {
        // write this just like a regular coroutine
        Debug.LogFormat( "{0}.{1}", 
                            GetType().Name, 
                            System.Reflection.MethodBase.GetCurrentMethod().Name );
        yield return null;
    }
}

public class DerivedClass : BaseClass
{
    protected override IEnumerator VInternalCoroutine()
    {
        // write this just like a regular coroutine
        Debug.LogFormat( "{0}.{1}", 
                            GetType().Name, 
                            System.Reflection.MethodBase.GetCurrentMethod().Name );
        yield return null;
    }
}

【讨论】:

    猜你喜欢
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    相关资源
    最近更新 更多