Unity3D Game Engineの「イールドリターンwww」の基本的なメカニズム


14

Unity3Dゲームエンジンでは、リモートデータを取得するための一般的なコードシーケンスは次のとおりです。

WWW www = new WWW("http://remote.com/data/location/with/texture.png");
yield return www;

ここにある基本的なメカニズムは何ですか?

ダウンロードの完了中に次のフレームを処理できるようにするために、yieldメカニズムを使用することを知っています。しかし、私たちが行うとき、ボンネットの下で何が起こっていyield return wwwますか?

どのメソッドが呼び出されていますか(もしあれば、WWWクラスで)?Unityはスレッドを使用していますか?「上位」Unityレイヤーはwwwインスタンスを取得して何かをしているのですか?

編集:

  • この質問は、特にUnity3D内部に関するものです。yieldC#でステートメントがどのように機能するかについての説明には興味がありません。代わりに、Unityがこれらの構造をどのように扱うかの内部ビューを探しています。たとえば、WWWが複数のフレームに分散した方法でデータをダウンロードできるようにするためです。

1
yield return非同期操作に使用することはハッキングであることに注意してください。「実際の」C#プログラムではTask、これを使用します。Unityは、.Net 4.0 Taskが導入される前に作成されたため、おそらく使用していません。
BlueRaja-ダニーPflughoeft 14

回答:


8

これはC#yieldキーワードの動作です- wwwオブジェクトに対して特別なことをするのではなく、含まれるメソッドに対して特別なことを意味します。具体的には、このキーワードはIEnumerable(またはIEnumerator)を返すメソッドでのみ使用でき、使用されますMoveNextが呼び出されたときに列挙子によって「返される」オブジェクトを示します。

コンパイラーはメソッド全体をステートマシンを使用して実装IEnumerable(またはIEnumerator)する別のクラスに変換するため、機能します。最終的な結果は、誰かが戻り値を列挙するまでメソッド自体は実行されないことです。これはどのタイプでも機能しますが、について特別なものは何もありませんが、特別なWWW包含メソッドです。

見てみましょうC#のyieldキーワードの舞台裏を、いくつかのC#コンパイラが生成するコードの一種どのように多くの洞察力、または単に実験のためにとのようなもの使ってコードを自分で調べILスパイ


更新:明確にするため

  • Unityがyield returnステートメントを含むコルーチンを呼び出すと、発生するのは列挙子が返されることだけです-この時点ではメソッド本体は実行されません
  • メソッド本体を取得してUnityを実行するにMoveNextは、シーケンスの最初の値を取得するためにイテレーターを呼び出す必要があります。これにより、メソッドは最初のyeild returnステートメントまで実行され、その時点で呼び出し元が再開します(おそらくUnityはフレームの残りの部分をレンダリングし続けます)
  • 私が理解しているように、Unityは通常、MoveNext後続のフレームごとにイテレータのメソッドを呼び出し、メソッドyield returnの最後またはyield breakステートメントのいずれかに達するまで、フレームごとに次のステートメントまでメソッドを再度実行しますシーケンスの終わり)

唯一の特殊ここビット(と中のカップル他の例では)ダウンロードが完了したとき(メソッドが実行を継続させる)代わりに、それが唯一のイテレータを進め、Unityは次のフレームこの特定のイテレータを進めないということです。おそらくイテレータを進める必要があるときにUnityに信号を送るための一般的なメカニズムを含む基本YieldInstructionクラスがあるように見えますが、WWWクラスはこのクラスから継承するようには見えないので、 Unityエンジンのこのクラス。

明確にするために、yieldキーワードはWWWクラスに特別なことをせず、Unityが返された列挙のメンバーに与える特別な処理により、この動作を引き起こします。


2番目の更新:WWW Webページを非同期でダウンロードするために使用するメカニズムについては、おそらく非同期IOを内部で使用するHttpWebRequest.BeginGetResponseメソッドを使用するか、スレッドを使用できます(専用スレッドを作成するか、スレッドプールを使用して)。


5
実際、Unityでは、WWWオブジェクトが生成されるとオブジェクトに何か特別なことが起こりWWWます
エリック

9

yield主にUnityでコルーチンコンテキストで使用されているようです。コルーチンの詳細とC#を使用する理由を読むyieldには、このブログ記事Unity3Dコルーチンの詳細をお勧めします。この回答の研究のほとんどは、その記事からのものです。

Unityのコルーチンは、次のタスクをカプセル化するために使用されます。

  1. レンダリングされるフレームよりも時間がかかる場合があります(それにより、スローダウンを引き起こします)。
  2. ゲームループとは別に実行できます(結果が現在のフレームで使用可能である必要がないため)。

これらの種類のタスクの例は、パスファインディング(再)計算、または質問の場合のように、Webサイトからデータを取得することです。

サブ質問に回答するには(わずかに変更した順序で):

どのメソッドが呼び出されていますか(もしあれば、WWWクラスで)?「上位」Unityレイヤーはwwwインスタンスを取得して何かをしているのですか?

UnityのWWWクラスは、コルーチンから生成されるように設計されています。上記のブログ記事へのコメントによると、YieldInstructions に関する投機的なコードブロック(「「上位」層」)には、実際にyieldをチェックするスイッチが含まれていますWWW。このコードは、WWW参考文献で説明されているように、ダウンロードが完了するとコルーチンが自動的に終了するようにします

Unityはスレッドを使用していますか?

この場合、「ゲームの残りの部分をブロックせずに」データをダウンロードする場合:はい、ほとんどの場合。(そして、明らかに、ダウンロードされたデータを解凍するためにスレッドが使用されWWW.threadPriorityます。)


いいね!コメントaltdevblogaday.com/2011/07/07/unity3d-coroutines-in-detail/を見ましたが、WWWは特別に扱われているようです。だから、スレッドを使用せずに複数のフレームにわたってダウンロードを行うことができるようにするために、これがどのように達成されるのかを知りたいですか?
thyandrecardoso

いい視点ね!結局、そのレベルで何らかのスレッド処理が行われているに違いないと思うので、それを反映するように回答を編集します。
エリック

1
私はそれを使用して推測するだろう@thyandrecardoso HttpWebRequest.BeginGetResponseまたは類似した、しかし、あなたはそれが本当にあなたに重要だった場合、これを確認するためにアセンブリコンパイルできます。
ジャスティン

今のところ、私は本当に「最高の説明」を待っているだけです... Unity開発チームの誰かが「正しい答え」を与えてくれたら素晴らしいと思います8-)...最終的に、本当の実装はそうではないと思いますすでにここで与えられているものからはほど遠い...しかし、アセンブリを逆コンパイルし、これをすべて確実に知る必要は実際にはない。しかし、私は後でそれを試すかもしれません:)
thyandrecardoso

7

残念ながら、WWWはネイティブコードとして内部的に実装されているため、コードを見ることができません。実験から、私はそれを言うことができます

  1. WWWはから派生したものではないYieldInstructionためyield、特別な場合のコードで処理する必要がある場合は何でも起こります。
  2. 私はこれまでにどんな違いも見たことがありません

    yield return www;

    そして

    while(!www.isDone)
        yield return null;

    私はそれがそれを実装する最も論理的な方法だと思います、そしておそらくそれは内部で起こっていることです。しかし、私は確かに知りません。

  3. Unityは、少なくとも一部のプラットフォーム(iOS、webplayer)では、ダウンロード用の新しいスレッドを開始しませ。または、その場合WWW.isDone、メインスレッドに設定します。このコードは次の理由で知っています。

    while(!www.isDone)
        Thread.Sleep(500);

    動作しません。

Unity3dのソースコードにアクセスできる人がここに来ない限り、より具体的な答えが得られるとは思いません。


うん。本当に素晴らしい洞察!ありがとう!スレッド自体を起動するわけではありませんが、最も可能性の高いことは、HttpWebRequest.BeginGetResponse(またはそれに似たもの)を使用したWWW(またはエンジン層)です。いずれかの方法で完全に非同期の何かが発生する必要があります...ダウンロードを「一時停止」することはできません。
thyandrecardoso

**フレーム間で「一時停止」することはできません。
thyandrecardoso

2

Unity3DはスクリプトエンジンとしてC#を使用しているため、C#に組み込まれている標準のyieldキーワードであると思います。基本的には、wwwの値を既に返しているので、次の反復が次の値を返す間、続行できます。Yieldは、基本的にバックグラウンドでステートマシンとイテレータを作成します。


はい、私はyieldキーワードについて基本的な考え方を持っていると思います。しかし、その「状態マシン」を可能にするWWWのコンストラクターで何が起きているのでしょうか?つまり、「yield return www」はWWWクラス内で何も呼び出していないようです。「wwwの値を既に返すということです」と言うとき、wwwインスタンスの値は何ですか。そのインスタンスは次の「反復」で何をしますか?
-thyandrecardoso

1
Unityコルーチンでは、WWWの生成は特別なケースです。WWW参考文献を参照してください。さらに、私はyield何かを作成するかどうかわからない。反復子コンテキストはIEnumerable、戻り型として実装または使用して作成されます。「ステートマシン」もオフのようです。確かに状態はありますが、それだけでは十分な財産ではありませんよね?たぶん、あなたはそれについて詳しく説明することができます。
エリック

1
通常のC#の動作に関する適切なリファレンスを次に示します。shadowcoding.blogspot.nl/2009/01/yield-and-c-state-machine.html。Yieldは、イテレーター内の位置を追跡するために多くのコードを生成します。WWWを生成するUnityの特殊なケースについては知りませんでしたが、ドキュメントによると、通常のC#キーワードとは何の関係もありません。
ロイT.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.