ハマったので備忘録です。
実行環境
Unity 2021.3.8f1
誤ったコード
using System.Collections;
using UnityEngine;
public class Test : MonoBehaviour
{
IEnumerator Start()
{
while (true)
{
if (Input.GetMouseButtonDown(0)) break;
Debug.Log("Looping");
yield return new WaitForEndOfFrame();
}
}
}
Coroutine内のwhileループにWaitForEndOfFrame()を用いた場合、
クリックしてもCoroutineを抜けられません。
修正したコード
using System.Collections;
using UnityEngine;
public class Test : MonoBehaviour
{
IEnumerator Start()
{
while (true)
{
if (Input.GetMouseButtonDown(0)) break;
Debug.Log("Looping");
yield return null;
}
}
}
nullを用いた場合、クリックするとCoroutineを抜けられます。
原因
Inputクラスの仕様
Input-GetKeyDown - Unity スクリプトリファレンスにて、Inputの説明を確認すると、
「You need to call this function from the Update function, since the state gets reset each frame. 」と書いてあります。
キー/マウス入力したフラグはフレームごとにリセットされるため、Update関数内で用いてください。と書いてありました。
Update関数ではない、コルーチン内では扱いがどうなるのでしょうか?
Unityのライフサイクル
イベント関数の実行順序 - Unity マニュアルを参照すると、
一番下にyield WaitForEndOfFramがあり、Updateのすぐ下にyield nullがあります。
「if a coroutine has yield previously but is now due to resume then execution takes place during part of the update.」
と書いてあるように、基本的には、yield nullはUpdate関数の一部として実行されるようです。
Inputクラスで入力したフラグがリセットされるのは、恐らくGameLogicの最後なのだと思われます。
そのため、whileループにWaitForEndOfFrameを用いてしまうと入力が受け取れません。
備考
using System.Collections;
using UnityEngine;
public class Test : MonoBehaviour
{
IEnumerator Start()
{
while (true)
{
if (Input.anyKey) break;
Debug.Log("Looping");
yield return null;
}
}
}
Input.anyKey、Input.GetMouseButton()、Input.GetKey()など
Downを伴わない入力を使うとwhileループを抜けられます。
こっちは入力フラグのリセットを行わず、キーを上げる動作を検出するまで
ずっとtrueになっているからなのだと思われます。(使う機会なさそう)
参考記事