怎么理解这个Unity Coroutine呢?

How to understand this Unity Coroutine?

using UnityEngine;
using System.Collections;

public class CoroutineExample : MonoBehaviour
{
    IEnumerator Start ()
    {
        print ("Starting " + Time.time);
        yield return StartCoroutine (WaitAndPrint ());
        print ("Done " + Time.time);
    }

    IEnumerator WaitAndPrint ()
    {
        yield return new WaitForSeconds (5f);
        print ("WaitAndPrint " + Time.time);
    }
}

结果是

Starting 0
WaitAndPrint 5.010554
Done 5.010554

我有两个问题?

首先,如何理解函数Start()的return值。我曾经看到 Start() 的 return 值是无效的。在我看来,Start() 仅由 Unity 执行一次(一帧),但 yield return 似乎使 Start() 函数在两帧中执行;

其次,我也对结果感到困惑。我认为结果应该是

Starting 0
Done 5.010554
WaitAndPrint 5.010554

因为StartCoroutine() 启动了函数WaitAndPrint()。在函数 WaitAndPrint() 中,yield return 使该函数在此帧暂停并 return 到 Start()。然后 Start() 继续进行并打印 "Done xxxxx"。 5 秒后,WaitAndPrint() 恢复并 打印 "WaitAndPrint xxxxx"。

我哪里错了?

IEnumerators 是迭代器块,它们不一定执行 1 帧,当您放置 yield return 时,您实际上是在告诉它迭代多个帧。

When a yield return statement is reached in the iterator method, expression is returned, and the current location in code is retained.

以下是我对这个结果的理解:

Unity 调用 Start() 函数一次并打印 "Started".

然后下一行做了两件事:

yield return StartCoroutine (WaitAndPrint ());
  • 它启动 WaitAndPrint() 协程
  • 它会等待它结束,然后再继续 Start() 协程。

WaitAndPrint() 协程将完成它的任务:

  • 等待 5 秒
  • 打印"WaitAndPrint"+时间

然后 Start() 协程将恢复并打印 "Done" + 时间。

这就是为什么

print ("WaitAndPrint" + Time.time);

打印在 :

之前
print ("Done " + Time.time);

此外,您应该编辑 post,它在第一个结果中遗漏了 space:

WaitAndPrint5.010554

应该是

WaitAndPrint 5.010554

抱歉,如果不清楚,这是我第一次在 Whosebug 上回答,希望对您有所帮助!

当您调用 yield return 时,控制权由 Unity 接管。

当您启动 Coroutine Unity 时,Unity 将采用 IEnumerator return 方法,并将在 IEnumerator [=50] 上调用 MoveNext =]ed.

根据对象的类型和对象中的值,Unity 将决定要做什么。

在你的情况下,在 Start 方法中 yield 语句 return 另一个 IEnumerator 所以 Unity 不会在 [=16= 上调用 MoveNext ] returned 对象直到第二个 IEnumerator 完成。

WaitAndPrint 中,第一个 MoveNext return 是一个 WaitForSeconds 对象,基于此,Unity 决定它 不会 在 5 秒后调用 MoveNext。 5 秒后它再次调用 MoveNext 并执行方法的其余部分,就是这一行

print ("WaitAndPrint" + Time.time);

yield return StartCoroutine (WaitAndPrint ()); 编辑的 IEnumerator return 结束时,它将在 return 编辑的 IEnumerator 上调用 MoveNext通过 Start,这将依次执行 Start:

的剩余部分
print ("Done " + Time.time);

希望这已经够清楚了:)

您可以 "nearly" 始终使用 Invoke 方法而不是 IEnumerators。尝试使用那个,你的生活会更轻松 :)