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:
Hướng dẫn thực hành
Định nghĩa IEnumerator
Method trả về IEnumerator với ít nhất một yield return.
Khởi động bằng StartCoroutine
Coroutine co = StartCoroutine(MyCoroutine()) — lưu tham chiếu để dừng sau.
Cache WaitForSeconds
Tạo một lần ở đầu class, tái dụng trong loop: _waitSec = new WaitForSeconds(0.5f).
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...
Ví dụ Code
Cơ bảnFadeOut 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 caoCoroutine 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);