はじめに
「StartCoroutineを書いているのに動かない…」
「エラーも出てないのに処理されない…」
「気づいたらUnityがフリーズしている…」
こういう状況、かなり多いです。私も最初は同じところで何度もハマりました🙂
Coroutineは便利な仕組みなんですが、
「動かない原因がコード上で見えにくい」のが厄介なんですよね。
例えばこんなケースがあります。
- GameObjectが非アクティブになっていて止まっている
- そもそもStartCoroutineが呼ばれていない
- yieldを書き忘れて実行されていない
- 無限ループでエディタが固まっている
どれも一見すると「ちゃんと書いているように見える」のがポイントです。
だからこそ大事なのは、
「どこを見れば原因が分かるのか」を知っておくことです。
Coroutineの不具合は、次の3つに分けると整理しやすくなります。
- 状態の問題(GameObjectや有効/無効)
- 書き方のミス(yield・StartCoroutineの呼び方)
- 設計の問題(多重起動・ループ構造)
この3つのどこかに必ず原因があります。
ここからは、実際によくある原因を「症状ベース」で分解していきます。
自分の状況と照らし合わせながら読み進めてみてください✨
結論:まず最初に確認すべき5つ
原因を細かく探す前に、まずはここをチェックしてみてください。
実際の開発でも、この段階で解決することがかなり多いです。
- GameObjectが非アクティブになっていないか
- StartCoroutineが本当に呼ばれているか
- コルーチン内にyield returnがあるか
- Updateで毎フレームStartCoroutineしていないか
- ループ内にyieldがなくフリーズしていないか
この5つは「発生頻度が高い順」に並んでいます。
特に多いのが次の2つです。
- GameObjectが非アクティブ → コルーチン自体が止まる
- Updateで多重起動 → 挙動が壊れる
ここを見落とすと、「コードは正しいのに動かない」という状態になります。
判断のコツとしては、こんな感じです。
- そもそも動かない → 呼び出し or 状態を疑う
- 途中で止まる → GameObjectやStop処理を疑う
- 挙動がおかしい → 多重起動を疑う
- 固まる → ループ構造を疑う
この時点で「あ、これかも」と思ったものがあれば、かなり当たりです🙂
次からは、それぞれの原因を1つずつ深掘りしていきます。
Coroutineが動かない原因と対処法
ここからは、実際によくある原因を「症状ごと」に分けて見ていきます。
自分の状況に近いものから確認していくと、かなり早く原因にたどり着けます。
GameObjectが非アクティブで動いていない
途中で処理が止まったり、そもそも動かなかったりする場合はまずここを疑います。
- 症状:途中で止まる / StartCoroutineしても動かない
- 原因:GameObjectがSetActive(false)になっている
- 解決方法:Hierarchyでアクティブ状態を確認する
UnityのCoroutineは、アタッチされているGameObjectに依存しています。
つまり、GameObjectが無効になるとコルーチンも止まります。
さらにややこしいのが、
再びアクティブに戻しても自動では再開されないという点です。
再発防止としては、こんな形にすると安定します。
void OnEnable()
{
StartCoroutine(MyCoroutine());
}
「気づいたら止まってる」系のトラブルは、ほぼここです。
StartCoroutineの呼び出し元が間違っている
コードは書いているのに、まったく動かない場合に多いパターンです。
- 症状:一切実行されない
- 原因:MonoBehaviourをnewで生成している
- 解決方法:AddComponentで生成する
例えばこれはNGです。
var obj = new MyScript();
obj.StartCoroutine(MyCoroutine());
Unityのスクリプトは、シーン上のGameObjectにアタッチされて初めて動きます。
newで作っただけでは、Unityの管理外になってしまいます。
正しくはこうです。
gameObject.AddComponent<MyScript>();
「C#としては正しいのに動かない」というときは、このパターンが多いです。
yieldがなくてコルーチンになっていない
IEnumeratorで書いているのに動かない場合、ここを確認します。
- 症状:すぐ終了する / エラーになる
- 原因:yieldが1つもない
- 解決方法:最低1つyieldを書く
Coroutineは「途中で止める」ことで成立しています。
yieldがないと、ただの関数と同じ扱いになります。
IEnumerator MyCoroutine()
{
Debug.Log("一瞬で終わる");
}
これだとコルーチンとして機能しません。
無限ループでフリーズしている
Unityが固まる場合は、ほぼこれです。
- 症状:エディタがフリーズする
- 原因:ループ内にyieldがない
- 解決方法:yield return nullを入れる
NG例はこちらです。
while (true)
{
// 何も待たない
}
これを実行すると、1フレーム内で無限ループが走り続けます。
その結果、Unityが応答しなくなります。
正しくはこうです。
while (true)
{
yield return null;
}
ループを書くときは、「毎回yieldしているか?」を必ず確認します。
Updateで毎フレームStartCoroutineしている
挙動がおかしくなる原因としてかなり多いです。
- 症状:動きが変になる / 重くなる
- 原因:毎フレーム新しいCoroutineが起動
- 解決方法:フラグ管理または1回だけ実行
よくある失敗例です。
void Update()
{
StartCoroutine(MyCoroutine());
}
これだと、毎フレーム新しいコルーチンが増え続けます。
対策はシンプルです。
bool isRunning = false;
void Update()
{
if (!isRunning)
{
StartCoroutine(MyCoroutine());
}
}
「とりあえずUpdateで呼ぶ」は、かなり危険なクセです。
StopCoroutineが効かない・エラーになる
止めたつもりなのに止まらない場合はここを見ます。
- 症状:止まらない / エラーになる
- 原因:対象のCoroutineが一致していない
- 解決方法:Coroutineを変数で保持する
Coroutine co;
co = StartCoroutine(MyCoroutine());
StopCoroutine(co);
文字列指定や別インスタンスを渡すと、うまく止まりません。
yield returnの使い方が間違っている
待機処理がうまく動かない場合は、ここが原因です。
- 症状:待機されない / タイミングがズレる
- 原因:用途に合っていないyieldを使用
- 解決方法:正しく使い分ける

例えば、毎フレーム処理したいのにWaitForSecondsを使うと、意図しない遅延が発生します。
「何フレーム待つのか」「何秒待つのか」を意識すると、ミスが減ります。
yield returnの正しい意味と使い分け
「yield return nullって結局なにしてるの?」という疑問、ここでスッキリさせておきましょう。
Coroutineの挙動は、この一行の理解でかなり変わります。
yield return nullの意味
結論から言うと、「次のフレームまで待つ」という意味です。
「何もしない」ではなく、処理を一旦止めて次のフレームに回す動きになります。
IEnumerator MyCoroutine()
{
Debug.Log("1フレーム目");
yield return null;
Debug.Log("2フレーム目");
}
この場合、ログは同時には出ません。
1フレームずれて表示されます。
この「フレームをまたぐ」性質が、Coroutineの本質です。
よく使うyieldの種類
実務でよく使うものを、用途とセットで整理しておきます。
| 書き方 | 意味 | 使う場面 |
|---|---|---|
| yield return null | 1フレーム待機 | 毎フレーム更新したい処理 |
| yield return new WaitForSeconds(1f) | 1秒待機 | 時間制御 |
| yield break | 即終了 | 条件で終了したい時 |
| yield return StartCoroutine(…) | 別Coroutineの完了待ち | 処理の順番制御 |
迷ったら、まずはこの2つを基準にすると分かりやすいです。
- 毎フレーム → yield return null
- 時間待ち → WaitForSeconds
よくあるミスと注意点
ここは実務でよく引っかかるポイントです。
- yield return 0
→ 一応動きますが、内部で変換が走るため基本は使いません - WaitForSecondsを毎回newしている
→ ループ内で使うとGC(メモリ確保)が増えます
例えばこういうコードは、長時間動かすと少しずつ負荷が増えます。
while (true)
{
yield return new WaitForSeconds(1f);
}
改善するなら、キャッシュして使います。
WaitForSeconds wait = new WaitForSeconds(1f);
while (true)
{
yield return wait;
}
体感レベルでは分かりにくいですが、モバイルや長時間プレイでは差が出てきます。
判断に迷ったときの考え方
迷ったらこの視点で考えるとスムーズです。
- フレーム単位で制御したい → null
- 時間で制御したい → WaitForSeconds
- 処理を分割したい → Coroutine

「何を待ちたいのか」をはっきりさせると、選び方で迷わなくなります。
Coroutineと他処理の違い
「Coroutineを使うべきか、それとも別の方法がいいのか」
ここがあいまいだと、バグの原因になりやすいです。
特に混同しやすいのがこの2つです。
- Updateとの違い
- async/await(Task)との違い
それぞれ整理していきます。
CoroutineとUpdateの違い
ざっくり言うと、こうなります。
| 項目 | Coroutine | Update |
|---|---|---|
| 実行タイミング | 必要なときだけ | 毎フレーム |
| 待機処理 | できる | できない |
| 用途 | 時間制御・段階処理 | 常時監視・入力処理 |
判断基準としては、これがシンプルです。
- ずっとチェックし続けたい → Update
- 一定時間待ちたい → Coroutine
例えばこんなイメージです。
- プレイヤーの入力監視 → Update
- 3秒後に爆発 → Coroutine
Updateで時間管理をしようとすると、こんなコードになります。
float timer = 0f;
void Update()
{
timer += Time.deltaTime;
if (timer > 3f)
{
// 実行
}
}
これでも動きますが、処理が増えるほど複雑になります。
Coroutineならシンプルです。
IEnumerator Explosion()
{
yield return new WaitForSeconds(3f);
// 実行
}
処理の流れがそのまま書けるのがメリットです。
より詳しく知りたい場合はこちらも参考になります。
Coroutineとasync/awaitの違い
中級者以上で気になってくるのがここです。
| 項目 | Coroutine | async/await |
|---|---|---|
| 仕組み | フレーム分割 | 非同期処理(スレッド) |
| Unity依存 | あり | なし |
| 主な用途 | ゲーム内の時間制御 | 通信・ファイル処理 |
大事なのはここです。
- Coroutine → ゲーム内の「時間の流れ」を制御
- async/await → 外部処理(通信・I/O)を待つ
例えば、
- 敵の行動を1秒ごとに変える → Coroutine
- サーバーからデータ取得 → async/await
この使い分けができると、設計がかなり安定します。

「なんとなくCoroutineで全部やる」は、後から崩れやすいポイントです。
すぐ確認できるチェックリスト
「原因を一つずつ読むのは大変…」というときは、ここから順番に確認すると早いです。
実際のデバッグでも、この順番で見るとほぼ迷いません。
3分以内で確認できる内容に絞っています👇
- □ GameObjectがアクティブになっているか
- □ StartCoroutineが実際に呼ばれているか(Debug.Logで確認)
- □ コルーチン内にyield returnがあるか
- □ whileやforの中にyieldが入っているか
- □ Updateで毎フレームStartCoroutineしていないか
- □ StopCoroutineの対象が正しいか
ポイントは、上から順に確認することです。
いきなり複雑な原因を疑うよりも、
「よくあるミス → 次に可能性の高いもの」と順番に潰す方が早く解決できます。
例えばこんな流れです。
- 動かない → StartCoroutineが呼ばれているか確認
- 途中で止まる → GameObjectの状態を確認
- おかしい → 多重起動を疑う
- 固まる → ループ構造を確認

このチェックを習慣にすると、
「なんとなくバグってる状態」から抜け出しやすくなります🙂
よくある誤解・注意点
Coroutineは「なんとなく動いている」状態でも成立してしまうので、
理解があいまいなまま使い続けてしまいがちです。
ここでは、実際によくある勘違いを整理しておきます。
Coroutine=非同期処理ではない
名前の印象で「非同期処理」と思われがちですが、少し違います。
Coroutineはスレッドを分けているわけではなく、1フレームずつ処理を分割しているだけです。
そのため、
- 重い処理を入れると普通にフレーム落ちする
- 並列で処理しているわけではない
という点は注意が必要です。
yield return null=何もしないではない
これもかなり多い誤解です。
実際には「次のフレームまで待つ」という意味があります。
この1行があるかどうかで、挙動が大きく変わります。
- ある → フレームごとに分割される
- ない → 一気に実行される
「何もしていないように見えるけど、実は重要」な行です。
一度止まったCoroutineは自動で再開しない
GameObjectが非アクティブになるとCoroutineは停止しますが、
元に戻しても勝手には再開されません。
この仕様を知らないと、「なんで動かないの?」と悩みやすいです。
必要なら、OnEnableなどで明示的に再スタートします。
一度動いたから正しいとは限らない
これが一番やっかいなポイントです。
例えば、
- たまたま1回だけ動いた
- 条件が偶然そろっていた
こういう状態でも「成功した」と思ってしまいがちです。
でも実際には、内部で問題を抱えていることが多いです。
判断の基準としてはこう考えると安全です。
- 毎回同じタイミングで動くか?
- 長時間動かしても崩れないか?
この2つを満たしていれば、かなり安定しています。
実務でのベストプラクティス
ここからは、実際に開発しているときに意識しておくと安定するポイントです。
「動く」だけでなく「壊れにくい」コードにするための考え方ですね。
多重起動を防ぐ
Coroutineのトラブルで一番多いのがこれです。
気づかないうちに複数起動してしまうと、
- 挙動が不安定になる
- 処理が重くなる
- StopCoroutineが効かなくなる
といった問題が出てきます。
対策はシンプルです。
bool isRunning = false;
IEnumerator MyCoroutine()
{
isRunning = true;
yield return new WaitForSeconds(1f);
isRunning = false;
}
そして呼び出し側で制御します。
if (!isRunning)
{
StartCoroutine(MyCoroutine());
}
「今動いているか?」を自分で管理するクセをつけると、かなり安定します。
Coroutineを変数で管理する
停止処理を確実にしたい場合は、Coroutineを保持します。
Coroutine co;
co = StartCoroutine(MyCoroutine());
StopCoroutine(co);
これをやらないと、
- 別のCoroutineを止めてしまう
- そもそも止まらない
といった問題が出やすくなります。
WaitForSecondsは使い回す
ループ内で毎回newするのは避けたいところです。
短時間では分かりにくいですが、長時間プレイやモバイル環境では影響が出てきます。
WaitForSeconds wait = new WaitForSeconds(1f);
while (true)
{
yield return wait;
}
「同じ時間で待つなら再利用する」と覚えておくとOKです。
状態管理とセットで使う
Coroutine単体で制御しようとすると、あとから破綻しやすいです。
例えば、
- 攻撃中フラグ
- 移動中フラグ
- クールタイム状態
こういった状態と組み合わせて使うと、挙動が安定します。
実務では「Coroutine+状態管理」が基本の形です。
経験からの判断基準
実際に開発していると、こういう場面に出会います。
- 動いているけど、たまにおかしくなる
- 再現性が低いバグが出る
このときに疑うべきは、
- 多重起動していないか
- 状態管理が抜けていないか
- Coroutineの開始・停止が曖昧になっていないか
Coroutineは「動いているように見えるバグ」が多いです。

だからこそ、
明示的に制御すること(状態・開始・停止)が大事になってきます。
おすすめ学習リソース
Coroutineでつまずく原因の多くは、実は「Unityの仕組み」と「C#の基礎」がつながっていないことにあります。
例えば、
- IEnumeratorの意味があいまい
- MonoBehaviourのライフサイクルが理解できていない
- Updateやフレームの概念がぼんやりしている
このあたりが整理されると、Coroutineの挙動が一気にクリアになります。
体系的に理解を深めたい場合は、こういった基礎をまとめて学べる書籍が役立ちます。
Unityの教科書 Unity 6完全対応版
✅ Amazonでチェックする|✅ 楽天でチェックする
断片的に調べるよりも、「全体像」を一度つかんでおくと、
エラーの原因を自分で判断できるようになります。

実際の開発では、Coroutine単体というよりも
「Unity全体の流れの中でどう動いているか」を理解しているかどうかで、安定度がかなり変わります。
まとめ
Coroutineが動かないときは、「なんとなくコードを見る」よりも、
原因のパターンに当てはめて確認する方が圧倒的に早いです。
まず最初に見るべきポイントはこの5つです。
- GameObjectがアクティブか
- StartCoroutineが呼ばれているか
- yield returnがあるか
- 多重起動していないか
- 無限ループになっていないか
そして、原因は大きくこの3つに分けられます。
- 状態の問題(アクティブ/非アクティブ)
- 書き方の問題(yield・呼び出し方法)
- 設計の問題(多重起動・管理不足)
この視点を持っておくと、「どこを見ればいいか」で迷わなくなります。
特に意識しておきたいのがこちらです。
- Coroutineはフレーム分割処理である
- 一度止まると自動では再開しない
- 動いていても正しいとは限らない
実務では「たまに動かない」「再現しにくいバグ」が一番厄介です。
そういうときは、
- 開始タイミングは明確か?
- 停止条件は明確か?
- 状態管理できているか?
この3つをチェックしてみてください。
Coroutineは便利ですが、仕様を理解していないと不安定になりやすい仕組みでもあります。
逆に言えば、仕組みを理解してしまえばかなり扱いやすくなります。
「なんで動かないんだろう…」と悩んだときは、今回のチェック項目に戻ってくると解決しやすくなります🙂
よくある質問(FAQ)
- QCoroutineはどんなときに使うべき?
- A
時間の経過や段階的な処理をしたいときに使います。
- 数秒後に処理を実行したい
- アニメーションのように順番に処理したい
- 一定間隔で処理を繰り返したい
逆に「毎フレーム常に監視する処理」はUpdateの方が向いています。
- QCoroutineが途中で止まるのはなぜ?
- A
最も多い原因は、GameObjectが非アクティブになっているケースです。
Unityでは、コルーチンはGameObjectに紐づいているため、
- SetActive(false)になる
- オブジェクトが破棄される
と、その時点で停止します。
再開したい場合は、OnEnableなどで再度StartCoroutineする必要があります。
- QCoroutineとUpdateはどちらを使うべき?
- A
目的によって使い分けます。
- 常に監視・入力処理 → Update
- 時間待ち・順番処理 → Coroutine
迷ったときは、「待機が必要か?」で判断すると分かりやすいです。








※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。
※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。