Coroutine
Coroutine は yield return で一時停止し、後で再開できる特殊なメソッドです。メインスレッドをブロックせずに、複数フレームにまたがるゲームロジックを書けます。WaitForSeconds のキャッシュ、コルーチン連鎖、StopCoroutine による停止の扱い方まで基礎を学べます。
想像してみてください...
Coroutine は本のしおりのようです。読んでいて(コード実行)、待ちに当たるとしおりを挟み(yield return)、他の作業へ。次フレームで Unity はしおりの位置から再開します。async/await と違い、コルーチンはメインスレッドに留まり——スレッドセーフが増えるわけではないが、Unity ライフサイクルに完全に組み込まれます。
概念の詳細
Coroutine は IEnumerator——C# のイテレータプロトコルです。各
yield return は yield instruction を返します:
null(1 フレーム待つ)、WaitForSeconds(t)、
WaitForFixedUpdate()、WaitUntil(predicate)…
StartCoroutine vs async: Coroutine は Unity の
メインスレッドで走り、すべての Unity API に触れられます。async/await は
(SynchronizationContext を保たない限り)別スレッドで再開し得ます。Coroutine は MonoBehaviour が
無効/破棄されると止まりますが、async は自動では止まりません。
WaitForSeconds をキャッシュ:
new WaitForSeconds(t) は呼び出しごとに割り当てます。保存して再利用:
var wait = new WaitForSeconds(2f); をループ内で使います。
停止: StopCoroutine() には
StartCoroutine が返す Coroutine ハンドルが必要です。
StopAllCoroutines() はその MonoBehaviour 上の全コルーチンを止めます。
ダイアグラム:Coroutine vs Update
❌ Update approach (polling)
void Update() {
if (Time.time > startTime + 2f)
DoAction(); // 毎フレームチェック!
}
⚡ 不要でも毎フレーム条件を確認
✅ Coroutine approach
IEnumerator Delayed() {
yield return new WaitForSeconds(2f);
DoAction(); // 1 回だけ実行
}
✅ 待機中は CPU を使わない
Coroutine の複数フレームタイムライン:
ハンズオン手順
IEnumerator を定義
IEnumerator を返し、少なくとも 1 つの yield return を持つメソッド。
StartCoroutine で開始
Coroutine co = StartCoroutine(MyCoroutine()) —— 後で止めるためにハンドルを保持。
WaitForSeconds をキャッシュ
クラス先頭で一度作りループで再利用:_waitSec = new WaitForSeconds(0.5f)。
必要時に停止
StopCoroutine(co)、または OnDisable で StopAllCoroutines()。
インタラクティブシミュレーター
Coroutine タイプを選び Start を押すと、フレームをまたいで進む様子を確認できます。
Code Execution
Frame Timeline
StartCoroutine を押す...
コード例
基本基本的な FadeOut 効果と遅延アクション。
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; // wait one 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();
}
}コード例
上級コルーチン連鎖(yield return で別コルーチン)と 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. Run another Coroutine and wait for it
yield return StartCoroutine(FadeToBlack(1.0f));
// 2. Load scene async
_loadingDone = false;
StartCoroutine(LoadSceneAsync());
// 3. Wait until load finishes (WaitUntil)
yield return new WaitUntil(() => _loadingDone);
// 4. Fade in the new scene
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;
}
}📌 要点
- ▸
yield return null= 1 フレーム待つ - ▸
new WaitForSeconds(t)をキャッシュ——毎フレーム GC を避ける - ▸GO が無効/破棄されるとコルーチンは止まる
- ▸連鎖には
yield return StartCoroutine()
⚠️ よくあるミス
❌ Coroutine 参照を残さない
ハンドルなしでは StopCoroutine を正確に呼べない
✅ _co = StartCoroutine(MyRoutine())
❌ while ループ内で new WaitForSeconds()
反復ごとに割り当て → GC スパム
✅ キャッシュ:var w = new WaitForSeconds(0.1f);