Unity Term Book
Scripting & Lifecycle

Coroutine

Coroutine là hàm đặc biệt có thể tạm dừng (yield return) rồi tiếp tục sau đó mà không block main thread — giúp logic gameplay trải dài qua nhiều frame.

Hãy tưởng tượng...

Coroutine giống như bookmark trong sách. Bạn đang đọc (chạy code), gặp đoạn cần chờ → đặt bookmark (yield return), gấp sách lại để làm việc khác. Frame sau, Unity mở sách ra, lật đến bookmark và đọc tiếp. Khác với async/await, coroutine chạy trên main thread — không thread-safe hơn, nhưng tích hợp hoàn toàn với Unity lifecycle.

Khái niệm chi tiết

Coroutine là IEnumerator — C# iterator protocol. Mỗi yield return trả về một yield instruction : null (đợi 1 frame), WaitForSeconds(t), WaitForFixedUpdate(), WaitUntil(predicate)

StartCoroutine vs Async: Coroutine chạy trên main thread Unity, có thể truy cập mọi Unity API. async/await dễ bị chạy trên thread khác (nếu không dùng SynchronizationContext). Coroutine dừng khi MonoBehaviour bị disable/destroy; async không tự dừng.

Cache WaitForSeconds: new WaitForSeconds(t) tạo object mỗi lần → GC alloc. Lưu vào biến và tái dụng: var wait = new WaitForSeconds(2f); dùng trong loop.

Dừng Coroutine: StopCoroutine() nhận tham chiếu Coroutine (từ StartCoroutine). StopAllCoroutines() dừng tất cả trên MonoBehaviour đó.

Sơ đồ: Coroutine vs Update

❌ Update approach (polling)

void Update() {

if (Time.time > startTime + 2f)

DoAction(); // check mỗi frame!

}

⚡ Check điều kiện mỗi frame dù không cần

✅ Coroutine approach

IEnumerator Delayed() {

yield return new WaitForSeconds(2f);

DoAction(); // chỉ chạy 1 lần

}

✅ Không tốn CPU khi đang chờ

Timeline thực thi Coroutine qua nhiều frame:

Start()
→ StartCoroutine
F1: chạy đến yield
⏸ pause
F2,F3: chờ...
F4: resume → done

Hướng dẫn thực hành

1

Định nghĩa IEnumerator

Method trả về IEnumerator với ít nhất một yield return.

2

Khởi động bằng StartCoroutine

Coroutine co = StartCoroutine(MyCoroutine()) — lưu tham chiếu để dừng sau.

3

Cache WaitForSeconds

Tạo một lần ở đầu class, tái dụng trong loop: _waitSec = new WaitForSeconds(0.5f).

4

Dừng khi cần

StopCoroutine(co) hoặc trong OnDisable dùng StopAllCoroutines().

Trình mô phỏng tương tác

Chọn loại Coroutine và nhấn Start để xem tiến trình thực thi theo frame.

Code Execution

Frame Timeline

Nhấn StartCoroutine...

Frame: 0|State: Idle|Chọn loại Coroutine và nhấn Start

Ví dụ Code

Cơ bản

FadeOut hiệu ứng và delayed action cơ bản.

using System.Collections;
using UnityEngine;

public class UIAnimator : MonoBehaviour
{
  private CanvasGroup _group;
  void Awake() => _group = GetComponent<CanvasGroup>();

  public void FadeOut(float duration)
  {
      StartCoroutine(FadeOutRoutine(duration));
  }

  private IEnumerator FadeOutRoutine(float duration)
  {
      float elapsed = 0f;
      while (elapsed < duration)
      {
          elapsed += Time.deltaTime;
          _group.alpha = 1f - (elapsed / duration);
          yield return null;  // đợi 1 frame
      }
      _group.alpha = 0f;
      gameObject.SetActive(false);
  }

  public Coroutine DoAfterDelay(float delay, System.Action action)
  {
      return StartCoroutine(DelayedAction(delay, action));
  }

  private IEnumerator DelayedAction(float delay, System.Action action)
  {
      yield return new WaitForSeconds(delay);
      action?.Invoke();
  }
}

Ví dụ Code

Nâng cao

Coroutine chain (yield return coroutine khác) và WaitUntil.

using System.Collections;
using UnityEngine;

public class LevelTransition : MonoBehaviour
{
  private bool _loadingDone = false;
  private readonly WaitForSeconds _framePause = new(Time.fixedDeltaTime);

  public void TransitionToNextLevel()
  {
      StartCoroutine(TransitionSequence());
  }

  private IEnumerator TransitionSequence()
  {
      // 1. Chạy Coroutine khác và đợi nó xong
      yield return StartCoroutine(FadeToBlack(1.0f));

      // 2. Load async scene
      _loadingDone = false;
      StartCoroutine(LoadSceneAsync());

      // 3. Đợi cho đến khi load xong (WaitUntil)
      yield return new WaitUntil(() => _loadingDone);

      // 4. Fade in scene mới
      yield return StartCoroutine(FadeFromBlack(0.5f));
  }

  private IEnumerator LoadSceneAsync()
  {
      var op = UnityEngine.SceneManagement.SceneManager
          .LoadSceneAsync("Level_02");
      op.allowSceneActivation = false;

      while (op.progress < 0.9f)
          yield return null;

      op.allowSceneActivation = true;
      _loadingDone = true;
  }
}

📌 Ghi nhớ nhanh

  • yield return null = đợi 1 frame
  • Cache new WaitForSeconds(t) — tránh GC mỗi frame
  • Coroutine dừng khi GO bị disable/destroy
  • yield return StartCoroutine() để chain coroutines

⚠️ Lỗi thường gặp

  • ❌ Quên lưu Coroutine reference

    Không thể StopCoroutine chính xác nếu không có reference

    ✅ _co = StartCoroutine(MyRoutine())

  • ❌ new WaitForSeconds() bên trong while loop

    Tạo object mỗi lần lặp → GC spam

    ✅ Cache: var w = new WaitForSeconds(0.1f);