2
votes
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);
    }
}

The result is

Starting 0
WaitAndPrint 5.010554
Done 5.010554

I have two questions?

First, How to understand the return value of function Start(). I used to see the return value of Start() is void. And in my view, Start() only executes once (one frame) by Unity, but yield return seems make Start() function execute in two frames;

Second, I am also confused by the result. I think the result should be

Starting 0
Done 5.010554
WaitAndPrint 5.010554

Because StartCoroutine() starts the function WaitAndPrint(). In function WaitAndPrint(), yield return makes this function pause in this frame and return to Start(). Then Start() continues going on and prints "Done xxxxx". After 5 seconds, WaitAndPrint() resume and prints "WaitAndPrint xxxxx".

Where am I wrong?

4

4 Answers

3
votes

Here's how I understand this result :

The Start() function is called once by Unity and prints "Started".

Then the following line does two things :

yield return StartCoroutine (WaitAndPrint ());
  • it starts the WaitAndPrint() coroutine
  • it waits for it to be over before continuing in the Start() coroutine.

The WaitAndPrint() coroutine will do its stuff :

  • Wait for 5 seconds
  • Print "WaitAndPrint" + time

Then the Start() coroutine will resume and print "Done" + time.

This is why

print ("WaitAndPrint" + Time.time);

is printed before :

print ("Done " + Time.time);

Also, you should edit your post, it misses a space in the first result :

WaitAndPrint5.010554

Should be

WaitAndPrint 5.010554

Sorry if it's not clear, it's my first time answering on StackOverflow, hope it helped !

3
votes

When you call yield return the control is taken by Unity.

When you start a Coroutine Unity will take the IEnumerator returned by the method and will call MoveNext on the IEnumerator returned.

Based on the type of object and on the values in the object Unity will decide what to do.

In you case in the Start method the yield statement return another IEnumerator so Unity will not call MoveNext on the Start returned object until the second IEnumerator finishes.

In WaitAndPrint the first MoveNext returns a WaitForSeconds object, based on that Unity decides that it will not call MoveNext on in until 5 seconds have passed. After 5 seconds it calls MoveNext again and the rest of the method is executed, which is just this line

print ("WaitAndPrint" + Time.time);

As the IEnumerator returned by yield return StartCoroutine (WaitAndPrint ()); reached its end it will call MoveNext on the IEnumerator that was returned by Start, this in turn will execute what ever is left of Start:

print ("Done " + Time.time);

Hope this is clear enough :)

0
votes

IEnumerators are iterator blocks, they dont necessarily execute for 1 frame, when you put a yield return, you essentially are telling it to iterate over multiple frames.

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

0
votes

Instead of IEnumerators you can "nearly" always use Invoke method. Try to work with that one and your life will be easier :)