質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

6830閲覧

while文の中のWaitForEndOfFrameの理解

GeeChiki

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2017/10/23 15:54

編集2017/10/24 04:51

イメージ説明unity公式の2Dshootingチュートリアルの敵集団をwaveを作る仕組みの中で、下記スクリプトが出てきました。

c#

1using UnityEngine; 2using System.Collections; 3 4public class Emitter : MonoBehaviour 5{ 6 // Waveプレハブを格納する 7 public GameObject[] waves; 8 9 // 現在のWave 10 private int currentWave; 11 12 IEnumerator Start () 13 { 14 15 // Waveが存在しなければコルーチンを終了する 16 if (waves.Length == 0) { 17 yield break; 18 } 19 20 while (true) { 21 22 // Waveを作成する 23 GameObject wave = (GameObject)Instantiate (waves [currentWave], transform.position, Quaternion.identity); 24 25 // WaveをEmitterの子要素にする 26 wave.transform.parent = transform; 27 28 // Waveの子要素のEnemyが全て削除されるまで待機する 29 while (wave.transform.childCount != 0) { 30 yield return new WaitForEndOfFrame (); 31 } 32 33 // Waveの削除 34 Destroy (wave); 35 36 // 格納されているWaveを全て実行したらcurrentWaveを0にする(最初から -> ループ) 37 if (waves.Length <= ++currentWave) { 38 currentWave = 0; 39 } 40 41 } 42 } 43}

この中の、

c#

1while (wave.transform.childCount != 0) { 2 yield return new WaitForEndOfFrame (); 3 }

の部分ですが、wave.transform.childCount != 0がfalseになった時に次のDestroy (wave);まで進むことができるという機能になっているかと思います。

しかし、このwhile文でなぜそうなるのか、ということが理解できません。

WaitForEndOfFrame のドキュメントの説明を見ると、「スクリーン上のレンダリングが完了するまで待ちます。」とあります。なぜレンダリングの話がでてくるのでしょうか。

また、wave.transform.childCount != 0がfalseになった時にDestroy (wave);に移るということは、もしかするとtrueの間はyield return new WaitForEndOfFrame ();はcontinueのような使われ方で、ループの先頭に戻る役割を担っているのでしょうか。つまり、falseになった瞬間にcontinueしなくなったので、次に進めたということかな、と。(だとしてもドキュメントの説明とつながらないように思えます)

何卒ご教授頂けると嬉しいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

質問主さんの仰る通り、「IEnumerator Start()」がコルーチンです。

「WaitForEndOfFrame」はレンダリング完了までの時間を指しますが、
このレンダリングというのは、いわゆる「フレーム」とほぼ同義です。
60fpsなら約0.016秒、30fpsなら0.033秒となります。

「yield return」は「一旦処理を中断し、returnの後ろに書かれた時間だけ待機し、その後次の行から再開する(=待機する)」命令です。

もしyield returnを挟まない場合、ずっと処理が続く為、それが完了するまで入力を受け付けることも出来ず画面が固まることになります。
(Unityの仕様上1つのプログラムの動作中は基本的に他のプログラムは動作せず、画面再描画(=レンダリング)もされない為)

なので実際の挙動は
「(wave.transform.childCount != 0)を判定→trueだった→yield returnで処理中断→レンダリングや入力を待つ→レンダリング完了(=1フレーム経過)→(wave.transform.childCount != 0)を再判定→trueだった→処理中断→レンダリングを待つ→……」
という繰り返しになり、結果的に
「Waveの子要素のEnemyが全て削除されるまで待機する」という処理になります。

こちらも参考になるかと思います。
Unity - マニュアル: イベント関数の実行順

投稿2017/10/24 01:36

sakura_hana

総合スコア11427

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

GeeChiki

2017/10/24 22:21 編集

非常にわかりやすいご回答、ありがとうございます! 私がちゃんと理解できているか、図を添付してみました。 (※1)が、1回目のyield returnの再開タイミング(レンタリング終了のタイミング)。その後、同じ0フレーム内で2回目のwhile (wave.transform.childCount != 0) {};に突入し、(※2)のタイミングで、次のレンダリング終了まで中断する。 という流れあっていますでしょうか。 もし正しいとすると、理解しづらかった理由は、1回目の中断はフレームをまたがず、2回目以降の中断ではフレームをまたいでいる点でした。yield return new WaitForEndOfFrame ();がフレーム単位で見た時に1回目も2回目も同じような処理になると勝手に思い込んでいたためです。
sakura_hana

2017/10/25 02:25 編集

私も正確に理解している保証は無い前提でお答えしますと…… 「1フレーム」を「回答内のリンク先で言うPhysics〜Pausingまで」とするならば、図の解釈で合っています。 フレーム0:ゲーム起動(Editor→Initializationと進行) フレーム0:Start()内で1回目のWhile判定、yield return開始 フレーム0:Initialization終了 フレーム1:フレーム開始(Physics→Input events→……と進行) フレーム1:End of frame到達時にyield return終了、2回目のWhile判定、yield return開始 フレーム1:Pausing完了、フレーム終了 フレーム2:フレーム開始(Physics→Input events→……と進行) フレーム2:End of frame到達時にyield return終了、3回目のWhile判定、yield return開始 フレーム2:Pausing完了、フレーム終了 (以降繰り返し) 「1回目のWhile判定はそもそもフレームのカウントが開始する前に行われる(=便宜上フレーム0としたが本当はフレームと呼べない=なのでフレームをまたぐこともない)」 「yield WaitForEndOfFrameは『常にEnd of frameタイミングまで待つ』(=1回目も2回目も同じ処理である)」 どちらも正しい認識だと思います。
GeeChiki

2017/10/25 05:49

なるほど!とても分かりやすいです。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問