強火で進め

このブログではプログラム関連の記事を中心に書いてます。

Coroutine(コルーチン)/yield(イールド)の話 その1

使った事の無い人には中々理解するのが大変なCoroutine(コルーチン)の説明。

実際のプログラムの動きを見てもらった方が手っ取り早いのでプログラムから。

function Start () {
	print ("Starting " + Time.time);
	yield WaitAndPrint();
	print ("-------Done " + Time.time);
}

function Update () {
	print ("Update " + Time.time);
}

function WaitAndPrint () {
	yield WaitForSeconds (1);
	print ("WaitAndPrint "+ Time.time);
}

この様な記述を行った場合は

	yield WaitForSeconds (1);

が実行された瞬間に WaitAndPrint() 関数は処理が終了します。
ここでは WaitForSeconds() の引数に1が指定して有るために1秒経過してから WaitAndPrint () 関数のそれ以降の処理が再開されます。

イメージ的には yield はreturn の様なイメージです。しかし、 return とは異なり、指定の時間が経過したら yield の次の行から処理が再開されます。

その為、コンソールに表示される文字は以下の順番となります。

「Start Starting」が表示
  ↓
「Update」が何度も表示
  ↓
1秒経ったら「WaitAndPrint」が表示
  ↓
直後に「-------Done」が表示

コンソール出力の時間が1秒の近辺を見ると上記の動作になっているが確認出来ます。

Update 0.9870263
UnityEngine.MonoBehaviour:print(Object)
NewBehaviourScript:Update() (at Assets/NewBehaviourScript.js:9)

Update 0.9958584
UnityEngine.MonoBehaviour:print(Object)
NewBehaviourScript:Update() (at Assets/NewBehaviourScript.js:9)

Update 1.002957
UnityEngine.MonoBehaviour:print(Object)
NewBehaviourScript:Update() (at Assets/NewBehaviourScript.js:9)

WaitAndPrint 1.002957
UnityEngine.MonoBehaviour:print(Object)
$:MoveNext() (at Assets/NewBehaviourScript.js:14)

-------Done 1.002957
UnityEngine.MonoBehaviour:print(Object)
$:MoveNext() (at Assets/NewBehaviourScript.js:5)

Update 1.011185
UnityEngine.MonoBehaviour:print(Object)
NewBehaviourScript:Update() (at Assets/NewBehaviourScript.js:9)

Update 1.020571
UnityEngine.MonoBehaviour:print(Object)
NewBehaviourScript:Update() (at Assets/NewBehaviourScript.js:9)

ちなみにコルーチンが使える場所には制限が有ります。 Start() では無く、 Awake() で以下の様に実行した場合は

function Start () {
	print ("Starting " + Time.time);
	yield WaitAndPrint();
	print ("-------Done " + Time.time);
}

以下の様にエラーが発生し、正しく動作しません。

Script error: Awake() can not be a coroutine.

Start() の yield WaitAndPrint(); を WaitAndPrint(); と変更し、以下の様にすると動作が変わります。

function Start () {
	print ("Starting " + Time.time);
	WaitAndPrint();
	print ("-------Done " + Time.time);
}

function Update () {
	print ("Update " + Time.time);
}

function WaitAndPrint () {
	yield WaitForSeconds (1);
	print ("WaitAndPrint "+ Time.time);
}

コンソールに表示される文字は以下の順番となります。

「Start Starting」が表示
  ↓
直後に「-------Done」が表示
  ↓
「Update」が何度も表示
  ↓
1秒たったら「WaitAndPrint」が表示

この場合であれば Start () を Awake () に変更し、以下の様に記述してもエラーとは成りません。

function Awake () {
	print ("Starting " + Time.time);
	WaitAndPrint();
	print ("-------Done " + Time.time);
}

Unity Script Reference – Coroutine
http://unity3d.com/support/documentation/ScriptReference/Coroutine.html