コルーチンを使うと、複数のフレームにタスクを分散させることができます。Unity では、コルーチンは、実行を一時停止して制御を Unity に戻し、次のフレームで中断した所から続行することができるメソッドです。
ほとんどの状況では、メソッドを呼び出すと、そのメソッドは、完了まで実行された後で、呼び出し元のメソッドに制御を返し、さらに任意の戻り値を返します。つまり、メソッド内で行われる全てのアクションは、1 回のフレーム更新中に行われる必要があります。
プロシージャルアニメーションや時経的なイベントのシーケンスを格納するためにメソッド呼び出しを使用したい場合には、コルーチンが使用できます。
ただし、コルーチンはスレッドではないことに注意してください。コルーチン内で実行される同期操作は、メインスレッドで実行されることに変わりありません。メインスレッドに費やされる CPU 時間を削減したい場合は、他の多くのスクリプトコードと同様に、コルーチン内でのブロック操作を避けることが重要です。Unity 内でマルチスレッドコードを使用したい場合は、C# ジョブシステム を検討してください。
HTTP 転送の待機、アセットのロードの待機、ファイル出入力の完了待ちなど、長い非同期処理を行う必要がある場合は、コルーチンの使用が最適です。
例えば、あるオブジェクトのアルファ (不透明度) の値を、見えなくなるまで徐々に下げるというタスクがあるとします。
void Fade()
{
Color c = renderer.material.color;
for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
{
c.a = alpha;
renderer.material.color = c;
}
}
この例では、Fade メソッドは、期待したような効果を発揮しない可能性があります。フェードが見えるようにするには、一連のフレームにわたってフェードのアルファを低下させることで、Unity のレンダリングする中間値を表示する必要があります。しかし、このサンプルメソッドは 1 回のフレーム更新中に全体が実行されます。中間値が表示されることはなく、オブジェクトは瞬時に消えます。
この状況は、フレーム単位でフェードを実行する Update
関数にコードを追加することで回避できます。ただし、この種のタスクには、コルーチンを使用する方が便利な場合があります。
C# では、以下のようにコルーチンを宣言します。
IEnumerator Fade()
{
Color c = renderer.material.color;
for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
{
c.a = alpha;
renderer.material.color = c;
yield return null;
}
}
コルーチンは、IEnumerator 戻り値型で宣言し、yield return ステートメントをボディのどこかに含むメソッドです。yield return null
の行は、実行が一時停止し、次のフレームで再開されるポイントです。コルーチンの実行を設定するには、以下のように StartCoroutine 関数を使用する必要があります。
void Update()
{
if (Input.GetKeyDown("f"))
{
StartCoroutine(Fade());
}
}
Fade 関数内のループカウンターは、コルーチンの生存期間を通して正しい値を保持し、全ての変数やパラメーターは yield
ステートメントと yield
ステートメントの間で保持されます。
デフォルトでは、Unity は yield
ステートメント直後のフレームでコルーチンを再開します。時間遅延を用いたい場合は、以下のように WaitForSeconds を使用します。
IEnumerator Fade()
{
Color c = renderer.material.color;
for (float alpha = 1f; alpha >= 0; alpha -= 0.1f)
{
c.a = alpha;
renderer.material.color = c;
yield return new WaitForSeconds(.1f);
}
}
WaitForSeconds
を使用して、効果を一定期間にわたって広げることができます。またこれは、Update
メソッドにタスクを含める代わりに使用することもできます。Unity は Update
メソッドを 1 秒間に数回呼び出すので、タスクをそれほど頻繁に繰り返す必要がない場合は、これをコルーチンに入れることで、毎フレームではなく定期的に更新されるようにできます。
例えば、以下のようなコードで、敵が近くにいることをプレイヤーに知らせるアラームをアプリケーションに含めたとします。
bool ProximityCheck()
{
for (int i = 0; i < enemies.Length; i++)
{
if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance) {
return true;
}
}
return false;
}
敵が数多く存在する場合は、この関数を毎フレーム呼び出すと著しいオーバーヘッドが生じる可能性があります。しかし、以下のようにコルーチンを使用して 1/10 秒ごとに呼び出すことも可能です。
IEnumerator DoCheck()
{
for(;;)
{
if (ProximityCheck())
{
// Perform some action here
}
yield return new WaitForSeconds(.1f);
}
}
このようにすれば、ゲームプレイに顕著な影響を与えることなく、Unity がチェックを行う回数を削減できます。
コルーチンを停止するには、StopCoroutine と StopAllCoroutines を使用します。また、コルーチンは、SetActive(false) を false
に設定してそのアタッチ先のゲームオブジェクトを無効にした場合にも停止します。Destroy(example)
(example
は MonoBehaviour インスタンス) を呼び出すと即座に OnDisable がトリガーされ、Unity がコルーチンを処理し、実質的にそれを停止します。最後に、OnDestroy
がフレームの最後に呼び出されます。
ノート: enabled を false
に設定することで MonoBehaviour
を無効にした場合、Unity はコルーチンを停止しません。
コルーチンは、他のスクリプトコードからは、異なる形で実行されます。Unity では、ほとんどのスクリプトコードは、パフォーマンストレース内で、特定のコールバック呼び出しの下の 1 箇所で出現します。ただし、コルーチンの CPU コードは、トレース内で常に 2 箇所に出現します。
コルーチン内の全ての初期コード (コルーチンメソッドの開始から最初の yield
ステートメントまで) は、Unity がコルーチンを開始した時にトレース内に表示されます。初期コードはほとんどの場合は StartCoroutine メソッドが呼び出された場所に表示されます。Unity コールバックが生成するコルーチン (例: IEnumerator
を返す Start
コールバック) は、最初にそれぞれの Unity コールバック内に表示されます。
コルーチンのその他のコード (初回の再開時点から実行完了まで) は、Unity のメインループ内の DelayedCallManager
ライン内に表示されます。
これが起こる理由は、Unity がコルーチンを実行する方法にあります。C#コンパイラー は、コルーチンに対応するクラスのインスタンスを自動生成します。その上で Unity がこのオブジェクトを使用して、1 つのメソッドの複数の呼び出しにわたってコルーチンの状態を追跡します。コルーチン内のローカルスコープ変数は複数の yield
呼び出しにわたって持続する必要があるため、Unity は、生成されたクラス内にローカルスコープ変数を巻き上げ、これはコルーチンの間中ヒープ上に割り当てられたままになります。また、このオブジェクトはコルーチンの内部状態の追跡も行います。つまり、yield 後にコードのどの時点でコルーチンが再開しなければならないかを記憶しています。
このため、コルーチンの開始時に掛かるメモリ負荷は、固定のオーバーヘッドコストにそのローカルスコープ変数のサイズを足したものに等しくなります。
コルーチンを開始させるコードがオブジェクトの構築と呼び出しを行い、その上で、そのコルーチンの yield
条件が満たされた時点で Unity の DelayedCallManager
がそれを再度呼び出します。通常はコルーチンは他のコルーチンの外で開始されるので、これにより、その実行オーバーヘッドが yield
呼び出しと DelayedCallManager
とに分割されます。
Unity のプロファイラーを使用すると、Unity がアプリケーションのどこでコルーチンを実行するかを調査し、理解することができます。これを行うには、Deep Profiling を有効にしてアプリケーションをプロファイリングします (これによりスクリプトコードの全ての部分がプロファイリングされ、全ての関数呼び出しが記録されます)。その上で、CPU Usage プロファイラーモジュール を使用してアプリケーションのコルーチンを調査できます。
一連の操作をできるだけ少ないコルーチンにまとめることをお勧めします。入れ子になったコルーチンは、コードの明瞭化と維持の面では便利ですが、コルーチンがオブジェクトを追跡するため、メモリオーバーヘッドが大きくなります。
ほぼ毎フレーム実行され、長時間実行される処理で yield
しないコルーチンがある場合は、これを Update
または LateUpdate
コールバックに置き換えるた方がパフォーマンスが向上します。これは特に、長時間実行されるコルーチンや無限にループするコルーチンにおいて有用です。
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.