How does this function with a "yield" work in detail?

Julius F picture Julius F · Aug 9, 2010 · Viewed 7.5k times · Source

I got this method (inside a Unity C# Script), but I do not understand how the "yield" part actually works.

I know from the MSDN that the function will return an IEnumerator which I could iterate throught, but this code waits 1,5 seconds and does not get iterated because this would mean, the objects created inside were created multiple times. Anyone here who can explain me how this code works?

IEnumerator DestroyShip()
{
    // create new gameobject
    Instantiate(ExplosionPrefab, transform.position, transform.rotation);
    // make current gameobject invisible
    gameObject.renderer.enabled = false;
    // set new position for the current gameobject
    transform.position = new Vector3(0f, transform.position.y, transform.position.z);
    // wait for 1,5 seconds 
    yield return new WaitForSeconds(1.5f);
    // make the current gameobject visible again
    gameObject.renderer.enabled = true;
}

Answer

Sjoerd picture Sjoerd · Aug 9, 2010

The Enumerator the compiler generates for you is being iterated. Once.

The compiler will generate a class that implements IEnumerator, which has a MoveNext() function and a Current property. The class will have all the members required to store the state of the function between calls. The exact details can be considered "Compiler Magic".

The object of this generated class, will be handled and managed by the Unity3d Engine. The Unity3d Engine will call MoveNext() on each active coroutine once every frame (unless instructed otherwise).

This enabled the Unity3d Programmer to write scripts that are played out one frame at a time. A combination of C# compiler magic and Unity3d Engine magic results in very-powerful-but-easy-to-use scripting.

To answer your question: the code in your function will be executed once, but it will pause at the 'yield return' statement.

As stated above, a special object that implements IEnumerator is created by the C# compiler.

On the first call to MoveNext(), your function creates an explosion and sets the current object to "new WaitForSeconds(1.5f)".

The Unity3d engine inspects this object, sees it is an instance of the special class "WaitForSeconds" so puts the enumerator on some waiting queue, and won't ask for the second element until 1.5 sec have passed. In the meantime, many frames will be rendered and the explosion will be played.

After 1.5 sec, Unity will grap the enumerator from the queue, and call MoveNext() again. The second part of your function will execute now, but will fail to generate a second object. MoveNext() will return false to indicate it failed to get a new element, which is the signal to Unity3d to throw this enumerator away. The Garbage Collector will reclaim the memory at some point in time.

As said: lots of compiler and Unity3d magic is going on. As long as you remember that your function will be put on hold till the next frame at each yield return statement, you'll know enough to benefit from those special functions.