Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

C# Dictionary

  1. Home
  2. C# Dictionary
  3. Coroutine / IEnumerator

Coroutine / IEnumerator

Since: C# 1.0(2002)

How to use coroutines in Unity to split processing across frames. A coroutine is a mechanism that can pause execution midway and resume in the next frame. Unity implements this internally using the IEnumerator interface. Define a method that returns an IEnumerator and start it with StartCoroutine().

Syntax

using System.Collections;
using UnityEngine;

// A method that returns IEnumerator is the body of a coroutine.
IEnumerator CoroutineName()
{
    // Pause execution and return control to the next frame.
    yield return null;

    // Wait for the specified number of seconds.
    yield return new WaitForSeconds(float seconds);

    // Wait until the next FixedUpdate.
    yield return new WaitForFixedUpdate();

    // Wait until the condition becomes true.
    yield return new WaitUntil(() => condition);
}

// Start the coroutine.
Coroutine handle = StartCoroutine(CoroutineName());

// Stop the coroutine.
StopCoroutine(handle);

// Stop all coroutines running on this GameObject.
StopAllCoroutines();

Method List

Method / ClassDescription
StartCoroutine(IEnumerator)Starts a coroutine. Storing the returned Coroutine handle lets you stop it later.
StopCoroutine(Coroutine)Stops the specified coroutine. Pass the value returned by StartCoroutine().
StopAllCoroutines()Stops all coroutines running on this component.
yield return nullPauses execution until the next frame.
yield return new WaitForSeconds(t)Pauses execution for t seconds. Affected by Time.timeScale.
yield return new WaitForSecondsRealtime(t)Pauses execution for t seconds in real time. Not affected by Time.timeScale (continues during pause).
yield return new WaitUntil(() => condition)Waits every frame until the condition becomes true.
yield return new WaitForFixedUpdate()Waits until the next FixedUpdate. Use this to synchronize with physics.

Sample Code

A sample coroutine that runs a countdown and blink effect in parallel.

CoroutineSample.cs
using System.Collections;
using UnityEngine;

public class CoroutineSample : MonoBehaviour
{
    private Coroutine blinkCoroutine;

    void Start()
    {
        // Start the countdown coroutine.
        StartCoroutine(CountDownCoroutine(5));

        // Store the handle so it can be stopped later.
        blinkCoroutine = StartCoroutine(BlinkCoroutine(0.5f));

        // Stop the blinking after 3 seconds.
        StartCoroutine(DelayedAction(3f, () =>
        {
            StopCoroutine(blinkCoroutine);
            Debug.Log("Blinking stopped.");
        }));
    }

    // A coroutine that counts down.
    IEnumerator CountDownCoroutine(int seconds)
    {
        for (int i = seconds; i > 0; i--)
        {
            Debug.Log($"Countdown: {i}");
            yield return new WaitForSeconds(1f);
        }
        Debug.Log("Go!");
    }

    // A coroutine that blinks the object.
    IEnumerator BlinkCoroutine(float interval)
    {
        Renderer rend = GetComponent<Renderer>();
        while (true)
        {
            if (rend != null)
                rend.enabled = !rend.enabled;
            yield return new WaitForSeconds(interval);
        }
    }

    // A coroutine that executes an action after a delay.
    IEnumerator DelayedAction(float delay, System.Action action)
    {
        yield return new WaitForSeconds(delay);
        action?.Invoke();
    }
}

Practical Pattern: WaitUntil for Condition-Based Waiting

A pattern that waits until a game state changes. Using WaitUntil keeps per-frame polling concise.

EnemySpawner.cs
using System.Collections;
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    private bool playerReady = false;
    private int waveCount = 0;

    void Start()
    {
        StartCoroutine(SpawnWaveCoroutine());
    }

    IEnumerator SpawnWaveCoroutine()
    {
        // Wait every frame until playerReady becomes true.
        yield return new WaitUntil(() => playerReady);

        waveCount++;
        Debug.Log($"Wave {waveCount} started.");

        SpawnEnemies();
        yield return new WaitForSeconds(30f);

        Debug.Log($"Wave {waveCount} ended.");

        // Start the next wave.
        StartCoroutine(SpawnWaveCoroutine());
    }

    void SpawnEnemies()
    {
        Debug.Log("Enemies spawned.");
    }

    public void SetPlayerReady()
    {
        playerReady = true;
    }
}

Practical Pattern: Nested Coroutines

Using yield return StartCoroutine() inside a coroutine waits for the inner coroutine to complete before continuing.

SequenceCoroutine.cs
using System.Collections;
using UnityEngine;

public class SequenceCoroutine : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(MainSequence());
    }

    IEnumerator MainSequence()
    {
        Debug.Log("Phase 1 start.");
        yield return StartCoroutine(PhaseOne()); // Waits for PhaseOne to complete.

        Debug.Log("Phase 2 start.");
        yield return StartCoroutine(PhaseTwo()); // Waits for PhaseTwo to complete.

        Debug.Log("All phases complete.");
    }

    IEnumerator PhaseOne()
    {
        yield return new WaitForSeconds(1f);
        Debug.Log("Phase 1 complete.");
    }

    IEnumerator PhaseTwo()
    {
        yield return new WaitForSeconds(2f);
        Debug.Log("Phase 2 complete.");
    }
}

Common Mistakes

Common Mistake 1: Coroutine Won't Stop

To stop a coroutine with StopCoroutine(), you must retain the Coroutine handle returned by StartCoroutine(). If you discard it, you can no longer stop that specific coroutine.

StopCoroutineNG.cs
using System.Collections;
using UnityEngine;

public class StopCoroutineNG : MonoBehaviour
{
    private Coroutine handle;

    void Start()
    {
        // NG: Discarding the return value means you cannot stop it later.
        StartCoroutine(BlinkCoroutine(0.5f));
    }

    // OK: Store the return value.
    void StartBlink()
    {
        handle = StartCoroutine(BlinkCoroutine(0.5f));
    }

    void StopBlink()
    {
        if (handle != null)
            StopCoroutine(handle);
    }

    IEnumerator BlinkCoroutine(float interval)
    {
        while (true)
        {
            yield return new WaitForSeconds(interval);
        }
    }
}

Common Mistake 2: Coroutine on Inactive GameObject

Coroutines only run while the MonoBehaviour is active. If SetActive(false) is called, coroutines stop and do not resume when the object is re-enabled.

using System.Collections;
using UnityEngine;

public class InactiveCoroutineNG : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(TimerCoroutine());

        // NG: Disabling the object stops the coroutine permanently.
        gameObject.SetActive(false);

        // OK: Stop all coroutines before disabling.
        // StopAllCoroutines();
        // gameObject.SetActive(false);
    }

    IEnumerator TimerCoroutine()
    {
        float elapsed = 0f;
        while (true)
        {
            elapsed += Time.deltaTime;
            Debug.Log($"Elapsed: {elapsed:F1}s");
            yield return null;
        }
    }
}

Overview

Coroutines run on the main thread, so there are no thread-safety concerns and you can call any Unity API freely. For long-running async operations such as HTTP requests, C#'s async / await is also available (Unity 2017 and later). Coroutines and async / await can coexist.

For Unity math functions, see Mathf; for vector math, see Vector2 / Vector3.

If you find any errors or copyright issues, please .