Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.
ロードオブナイツで使ってるUnity非同期処理デザイン          ++C++; 岩永信之               2012/10/12
イテレーター構文とUnityのコルーチンコルーチン
ゲーム ループ●   ゲームでは、どこか大元でループが回ってる     while (isAlive)     {         // 固定 FPS なら、所定の時間が来るまで Sleep         gameTime = … // ゲー...
重たい処理●   フレームレートよりも時間がかかる処理をし    ちゃダメ    ダメな例    string Load(string path)    {        // 30ミリ秒くらいかかるものとする        var data ...
そこで、イテレーター●   イテレーターをコルーチンとして使うゲーム ループ中で、毎フレーム MoveNextを呼んでもらう    IEnumerator Load(string path, Action<string> callback)  ...
before/after (1)●   メソッド宣言    before    string Load(string path)    after    IEnumerator Load(string path, Action<string> ...
before/after (2)●   return    before     return result;    after     callback(result);     ●   returnステートメントの代わりにcallback呼...
before/after (3)●    呼び出し側    before    var x = Load("path"); …(後続の処理)    after    StartCoroutine(Load("path", x => { …後続の...
.NET Framework 4のTaskクラスを参考に、UnityコルーチンをラッピングTASKクラス
問題●   複数のコルーチンを扱いにくい     StartCoroutine(A);     StartCoroutine(B);        ●   A, B両方が完了するのを待ちたいときはどうする?        ●   Aの完了後にB...
Taskクラス●   こういうクラスを用意        public class Task<T> : IEnumerator        {            IEnumerator Routine;            public...
実例●   ロードオブナイツのマップ    ●   64万要素程度の配列をJSONで受け取ってた         ● 通信もコルーチン            ●   通信エラーが発生する可能性あり        ●   デコードもそこそこ高負荷...
Task利用例(戻り値)●   (本来の)戻り値の伝播     IEnumerator A(Action<int> callback);     IEnumerator B(int x, Action<string> callback);   ...
同期処理と比べて●   同期処理との対比     IEnumerator A(Action<int> callback);     IEnumerator B(int x, Action<string> callback);     IEnum...
Task利用例(例外処理)●   コルーチン内で発生した例外も受け取れる    var t = new Task<int>(A)        .ContinueWith<string>(B)        .ContinueWith(C)  ...
以上
Próxima SlideShare
Cargando en…5
×

Async design with Unity3D

92.219 visualizaciones

Publicado el

UnityでHTTP通信をするときに割りと困りがちな非同期処理の設計についてロードオブナイツで使っているデザインを公開します。スライド作成は++c++;の中の人。

Publicado en: Tecnología

Async design with Unity3D

  1. 1. ロードオブナイツで使ってるUnity非同期処理デザイン ++C++; 岩永信之  2012/10/12
  2. 2. イテレーター構文とUnityのコルーチンコルーチン
  3. 3. ゲーム ループ● ゲームでは、どこか大元でループが回ってる while (isAlive) { // 固定 FPS なら、所定の時間が来るまで Sleep gameTime = … // ゲーム時間を進める foreach (var obj in gameObjects) { obj.Update (gameTime); } } 1フレームに1回よばれる処理
  4. 4. 重たい処理● フレームレートよりも時間がかかる処理をし ちゃダメ ダメな例 string Load(string path) { // 30ミリ秒くらいかかるものとする var data = ファイルからバイナリロード(path);     // これも30ミリ秒くらいかかるものとする return デシリアライズ(data);     // 30 FPSだと、このメソッドは33ミリ秒以内に終えないと処理落ち } 2回に分けたい
  5. 5. そこで、イテレーター● イテレーターをコルーチンとして使うゲーム ループ中で、毎フレーム MoveNextを呼んでもらう IEnumerator Load(string path, Action<string> callback) { var data = ファイルからバイナリロード(path); 1フレーム目     yield return null; callback(デシリアライズ(data)); 2フレーム目     yield return null; } returnの代わりに コールバック呼び出し
  6. 6. before/after (1)● メソッド宣言 before string Load(string path) after IEnumerator Load(string path, Action<string> callback) ● 戻り値はIEnumerator固定 ● 本来の戻り値はcallbackごしに返す
  7. 7. before/after (2)● return before return result; after callback(result); ● returnステートメントの代わりにcallback呼び出し
  8. 8. before/after (3)● 呼び出し側 before var x = Load("path"); …(後続の処理) after StartCoroutine(Load("path", x => { …後続の処理 }); ● 戻り値を直接受け取れない ● 形式上の戻り値(IEnumerator)はコルーチン起動のた めに使う ● 匿名関数を使って後続の処理をつなぐ
  9. 9. .NET Framework 4のTaskクラスを参考に、UnityコルーチンをラッピングTASKクラス
  10. 10. 問題● 複数のコルーチンを扱いにくい StartCoroutine(A); StartCoroutine(B); ● A, B両方が完了するのを待ちたいときはどうする? ● Aの完了後にBを開始したいときはどうする? ● 特に、Aの(本来の)戻り値をBで使いたいときは? ● エラーの伝播を考えるとさらに面倒
  11. 11. Taskクラス● こういうクラスを用意 public class Task<T> : IEnumerator { IEnumerator Routine; public T Result { get; } public Exception Error { get; } public void OnComplete(… callback); public Task<T> ContinueWith<U>(… continuation); } ● 継続処理の登録 ● (本来の)戻り値やエラーの伝播
  12. 12. 実例● ロードオブナイツのマップ ● 64万要素程度の配列をJSONで受け取ってた ● 通信もコルーチン ● 通信エラーが発生する可能性あり ● デコードもそこそこ高負荷なのでコルーチン化したい ● (行単位でデコード、1フレームに1行ずつとか) ● 通信の結果を使う ● デコード エラーが発生する可能性あり ● ローカル ストレージにキャッシュしたい ● IOエラーが発生する可能性あり※ 最新バージョンではデータを小分けで受信するように改善され、デコード処理はコルーチンではなくなっている
  13. 13. Task利用例(戻り値)● (本来の)戻り値の伝播 IEnumerator A(Action<int> callback); IEnumerator B(int x, Action<string> callback); IEnumerator C(string s); A, B, C の順で実行したい A の戻り値(int)を B で、B の戻り値(string)を C で使いたい 同期処理なら C(B(A()); だけで書けるもの var t = new Task<int>(A) .ContinueWith<string>(B) .ContinueWith(C); StartCoroutine(t);
  14. 14. 同期処理と比べて● 同期処理との対比 IEnumerator A(Action<int> callback); IEnumerator B(int x, Action<string> callback); IEnumerator C(string s); int A(); string B(int x); void C(string s); var t = new Task<int>(A) var x = A(); .ContinueWith<string>(B) var s = B(x); .ContinueWith(C); C(s); StartCoroutine(t); あるいは C(B(A()));
  15. 15. Task利用例(例外処理)● コルーチン内で発生した例外も受け取れる var t = new Task<int>(A) .ContinueWith<string>(B) .ContinueWith(C) .OnComplete(t => ● A, B, C のどこかで例外が発 { 生した場合、そこでコルーチン if (t.Error != null) … の実行は中断。 }); ● 発生した例外はErrorプロパ ティにセットされる StartCoroutine(t);
  16. 16. 以上

×