テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

UnityのCoroutine(コルーチン)でできる事のメモ

目次

n秒後に何かする

f:id:tsubaki_t1:20150406003500g:plain

コルーチンは、時間を絡めた処理を実装するのに便利です。例えば以下のように記述すると、以下の様なフローが記述出来ます。

  1. オブジェクトをクリックした際、色を「赤」へ変更
  2. 0.5秒待つ
  3. 対象のオブジェクトの色を「緑」に戻す

gist.github.com

yield return null;を使用すると次のフレームまで、yield return new WaitForSeconds(秒数);を使用すると指定秒停止します。

コルーチンとして実行できる処理は、戻り値がIEnumeratorのメソッドのみです。

ちなみにStartCoroutine_Autoなるメソッドが有りますが、これはStartCoroutineの実装部分です。要するに、 StartCoroutineはStartCoroutine_Autoを呼んでるだけです。

コルーチンの停止

コルーチンの処理を中断させるには、yield break を使用します。例えば既にコルーチンが起動していた場合、処理を中断する等に使えます。

gist.github.com

Coroutineを停止させるには、StopCoroutineを使用します。

なおStopCoroutineはコルーチン側へ終了を通知する方法ありません。もし何らかのフラグ処理(例えばコルーチンが開始中等)をコルーチンが行っていた場合は、StopCoroutineを行う側が責任持ってフラグを何とかします。またstopCoroutineで止めると、disposeやfinallyが呼ばれない点も注意が必要です。

gist.github.com

コルーチンの一時停止

f:id:tsubaki_t1:20150406053208g:plain

メソッドのIEnumeratorを事前に取得し、取得したIEnumeratorコルーチンをスタートする場合、コルーチンを停止した後に停止したポイントから再開する事ができます。

gist.github.com

なお一度完走したコルーチンを最初からやり直す場合、新しくメソッドからIEnumeratorを取得する必要があります。

コルーチンの完了を待ち合わせる

複数のコルーチンを待ち合わせたい場合、コルーチンの中でコルーチンの終了を待ちます。例えば下のgifアニメは以下のフローに従って動いています。

  1. ボタンを押すと、ボタンが青くなる
  2. 左の球を緑から赤に変更する(一定時間後に緑に戻る)
  3. 右の球を緑から赤に変更する(一定時間後に緑に戻る)
  4.  両方の球が緑に戻るのを待つ
  5. ボタンの色を白に戻す。

これは例えば「複数のアニメーションが終わるまで待つ」や「ダウンロード終わったら処理を開始する」といった場合に使えます。

f:id:tsubaki_t1:20150406013650g:plain

gist.github.com

なお、この方法はキャンセルに若干面倒な所があります。というのも、コルーチンはStopCoroutineを検知する事ができないので、親のコルーチンが止まっても子が生き残るって事が発生します。なので、親を止める場合は子も一緒に停止してもらいます。

gist.github.com

面倒ならGameObjectを非アクティブにすれば止まります。

コルーチンの結果を受け取る

コルーチンはrefやoutが使えないので、ActionもしくはUnityActionを使用して戻り値を取得します。

gist.github.com

もしくはUnity3D - Unity のコルーチンで結果を受け取るで紹介されててはじめて気づきましたが、コルーチンの最後に戻り値となる値を仕込んでおき、IEnumeratorで取得するといったアイディアがあります。型指定が必要ですがコレが一番読みやすいです。

gist.github.com

フィールド変数にパラメータを持たせるアイディアもあるにはありますが…それをするならばコルーチン専用のクラスを用意したい所です。

gist.github.com

進行状況が表現可能な 待機

コルーチンでWaitForSecondsで止めると、その秒数経つまで処理が呼ばれません。それが困るケースが有る場合、WaitForSecondsを以下のように修正することで、待機中の進行状況を表現したり出来ます。下の画像は、1秒間で色のフェードを行います。

f:id:tsubaki_t1:20150406034527g:plain

やっている事は単純で予定終了時刻を取得して、予定終了時刻を超えたらループを抜けるといった感じです。ループ内でyield return nullを呼ぶのがポイントです。

今回の場合、予定終了時刻から現在時刻を引いて進行度合いを取得、その値を元に色をフェードしています。

gist.github.com

今回は進行として「終了時刻」を使いましたが、while(終了条件){ yield return null;} を使えば、大体の条件を使って処理の待機が可能です。

その他Tips

  • 親のGameObjectが非アクティブになると動作を停止します。
  • コンポーネントがenable/disableになっても動作を継続します。
  • スクリプト最適化アプローチの一つとして、コルーチンをUpdateの変わりに使用する方法が、GDC等でたまに紹介されます。たぶん「数秒スキップ」できる事がミソです。
  • OnMouseDownやOnCollisionEnterといったMonobehaviourのもつ幾つかのメソッドはコルーチン化して呼び出すことが出来ます。

    f:id:tsubaki_t1:20150406042425g:plain

  • コルーチンはメインスレッド上で動作しています。

参考

ゲームは初心者にやさしく: 必見!Unity初心者が学ぶ「未来事象の正しい文法」

Coroutine(コルーチン)/yield(イールド)の話 その1 - 強火で進め

Unityのコルーチンの使い方をまとめてみた | ワンダープラネットエンジニア Blog

[Unity] 引数にIEnumratorを指定したStopCoroutineの使い方 : West Hill 開発メモ

Unity3D - Unity のコルーチンで結果を受け取る - Qiita

G-MODE Engineers' Blog — StartCoroutineは何をしているのか?作って学ぶコルーチンの仕組み(前編)

G-MODE Engineers' Blog — StartCoroutineは何をしているのか?作って学ぶコルーチンの仕組み(後編)