Coroutines with Unity

by Lance Gold

After script logic is workable for one shooter in a shooting game, manage repeat challenges with a spawn manager.

Return to index

Difficult logic: respawn a target when each target falls out of view, destroyed, or when each target is destroyed after a hit to the Player.

Easier logic: ignore targets after Instantiation, and respawn new targets after a fixed or random time period.

Create an Empty Object to contain the manager script code.

Create Empty to hold script

Create Empty to hold script

The new Spawn Manager is a GameObject with components

Spawn_Manager GameObject

Spawn_Manager GameObject

Mouse over to the Scripts folder in the Project window and right click to create a new C# Script.

Created SpawnManager in Scripts folder

Created SpawnManager in Scripts folder

Drag and drop the script onto the Spawn_Manager GameObject in the Hierarchy.

Script now included in GameObject

Script now included in GameObject

How to Instantiate and Delay

Coroutines allow pauses in an object’s function, to wait.

From the Unity manual:

Coroutines

A coroutine allows you to spread tasks across several frames. In Unity, a coroutine is a method that can pause execution and return control to Unity but then continue where it left off on the following frame.

In situations where you would like to use a method call to contain a procedural animation or a sequence of events over time, you can use a coroutine.

Here is a C# method of type “void” with a “null return” (not a coroutine, no slow motion):


void myMethod()
{
 ...
  return;
}

Here is a coroutine of “type IEnumerator” with a “yield return null” from the manual:


IEnumerator Fade()
{
    Color c = renderer.material.color;
    for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
    {
        c.a = alpha;
        renderer.material.color = c;
        yield return null;
    }
}

The IEnumerator combined with the yield can hold up the Unity Update loop for a few steps.

MonoBehaviour.StartCoroutine

Declaration

public Coroutine StartCoroutine(IEnumerator routine);

Description

Starts a Coroutine.

The execution of a coroutine can be paused at any point using the yield statement. When a yield statement is used, the coroutine pauses execution and automatically resumes at the next frame.

Unity — Scripting API: MonoBehaviour.StartCoroutine


public class SpawnManager : MonoBehaviour
{
    private IEnumerator coroutine;

    void Start()
    {
        Debug.Log("starting coroutine");
        coroutine = SpawnRoutine(5.0f);
        StartCoroutine(coroutine);
    }
...
    IEnumerator SpawnRoutine(float waitTime) // 5 seconds
    {
        while (true)
        {
            yield return new WaitForSeconds(waitTime);  // 5 seconds
            Debug.Log("waiting" + Time.time);       // elapsed time
        }
    }
}

(a) “private IEnumberator cotoutine” is outside the methods.

(b) WaitAndPrint(2.0f); and StartCoroutine( … ) are called inside “void Start(){ … }”;

(c) “yield return new WaitforSeconds(waitTime);” is inside infinite loop inside the IEnumerator declaration

(d) Example class “SpawnManager” is an added component C# Script added to a create empty object “Spawn_Manager” in the Hierarchy list.

Example game run with coroutine messages

Example game run with coroutine messages

Managing a GameObject

(a) Create [Serialize] private GameObject _enemyPrefab;

(b) run and address “UnassignedReference…” exception

Enemy Prefab unassigned

Enemy Prefab unassigned

Highlight the Hierarchy Game Span_Manager and Drag the Project Assets Prefabs Enemy to the “None (Game Object…” in the Inspector.

Enemy Prefab assigned

Enemy Prefab assigned

(c) Add the Instantiate(…) code


public class SpawnManager : MonoBehaviour
{
...
   IEnumerator SpawnRoutine(float waitTime)
    {
        while (true)
        {
            // instantiage Enemy
            _horizontalRandom = UnityEngine.Random.Range(_leftEdge, _rightEdge);
            transform.position = new Vector3(_horizontalRandom, _topEdge, 0);

            Instantiate(_enemyPrefab, transform.position, Quaternion.identity);

            yield return new WaitForSeconds(waitTime);
        }
    }
}