Progression FrameworkのFuncコマンド+loader.loadでロード失敗すると、もうどうしようもない疑惑

  • このエントリーをはてなブックマークに追加
  • 80

Progression Frameworkのコマンド使ってみよう大会継続中だが、今回はLoaderクラスとFuncコマンドを使ってロード完了待ちをしようと言うテクニックと、発生した問題点について述べたいと思う。
Funcコマンドを使った方法は、

こちらを参考にしてみた。

■Funcコマンドでデータ読み込み

さて、Funcコマンドを使った読み込みだが、このような感じになる。

ActionScript

  1. var loader:CastLoader = new CastLoader();
  2. loader.contentLoaderInfo..addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {
  3.     trace("読み込み失敗(IO):", sceneId, url, e);
  4. });
  5. loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:SecurityErrorEvent):void {
  6.     trace("読み込み失敗(SEC):", sceneId, url,e);
  7. });
  8. addCommand(
  9.     new Func(null, loader.load, [new URLRequest("image.jpg")], 0,
  10.              loader.contentLoaderInfo, Event.COMPLETE),
  11.     new AddChild(progression.container , loader , true),
  12.     new Goto(children[0].sceneId)
  13. );

これで、画像「image.jpg」を読み込み、読み込みが完了したら画面に表示して、最後に次のシーンに移動すると言う処理になっている。この簡単なコードでこの処理。Progression Frameworkは偉大だ。

■うまくいくとは限らない

ただし、これは画像がうまく読み込めたらの話。
じゃあ、例えばURLが間違ってたり、その他の理由で画像が読み込めない状況になったらどうなるか?
こうなる。
簡単に言うと、「何も出来なくなる」。
画像は勿論表示されないし、次のシーンに移動もしない。
それどころか、他のボタンを押しても何も起きない。処理が完全に停止し、どうしようもなくなるようなのだ。

何故か!?
それはこれ。

ActionScript

  1. new Func(null, loader.load, [new URLRequest("image.jpg")], 0, loader.contentLoaderInfo, Event.COMPLETE),

Funcに指定できる、「あるオブジェクトがあるイベントを送出するまで、処理を停止する」機能のせいだ。
この例の場合だと、loader.contentLoaderInfoから画像読み込みが完了したことを示すEvent.COMPLETEが送出されるまで、コマンドは処理を停止し、待ち続ける。
が、読み込み失敗時には、その原因に応じてIOErrorEvent.IO_ERRORSecurityErrorEvent.SECURITY_ERRORなどが送出され、Event.COMPLETEが送出されないままで読み込みは終了する。
で、そのままFuncコマンドはずーっと待ちぼうけし続け、以降のコマンドは全く実行されないと言うわけだ。

さらに、addCommandで一気にコマンドを追加すると、全部が終了するまで他の処理が行われないらしい。前回のエントリで書いた並列実行と直列実行のサンプルでも、直列実行時に一番上のボタン0を押しても何も起きない。すべてのボタンが出終わってからでないと、ボタンの動作が無視されるようなのだ。

■更なる悲劇が!

さて、ではエラー時はどうすればいいのか?
取り敢えず、エラーイベントを拾ったらおとなしく他のシーンに移ってはどうか?

ActionScript

  1. var loader:CastLoader = new CastLoader();
  2. loader.contentLoaderInfo..addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {
  3.     trace("読み込み失敗(IO):", sceneId, url, e);
  4.     new Goto(progression.root.sceneId).execute();
  5. });
  6. loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:SecurityErrorEvent):void {
  7.     trace("読み込み失敗(SEC):", sceneId, url,e);
  8. });
  9. addCommand(
  10.     new Func(null, loader.load, [new URLRequest("image.jpg")], 0,
  11.              loader.contentLoaderInfo, Event.COMPLETE),
  12.     new AddChild(progression.container , loader , true),
  13.     new Goto(children[0].sceneId)
  14. );

と言うわけで、失敗したらルートシーンに戻ると言う事にしてみた。
さて問題!
ココで注意すべき点があります。このコードを書いてはいけない場所はどこ?




答え:_onLoadメソッド内。
今回のコード例だと、コードがあるシーンはルートの子で、行き先は自分の子、つまりルートの孫になる。
なので、エラー時にルートに移動するとどうなるか?

  1. 画像読み込み(Func)開始
  2. IOエラー発生。ルートへ移動
  3. シーンが移動し、画像読み込み用のFuncコマンド停止
  4. 画像表示(AddChild)開始
  5. シーン移動(ルートの子の子へのGoto)開始
  6. ルート→孫への移動の過程で、画像読み込みシーンの_onLoad実行
  7. 1.に戻る

このように無限ループに陥ってしまう。
ミソは、シーンを移動してもFuncが終わるだけで、後続のコマンドが実行されると言う点。
なので、画像読み込みは_onInitに書かないとダメ。

まぁ、この辺りはシーン移動のパズルだな。
ちゃんと理解して上手く考えないと、ヒドイ目に逢いますよと言う話。プログラムの世界じゃよくある事だ。

と言うわけで、_onInitにaddCommandを移したバージョンはこちら
画像読み込み失敗でも、ちゃんとシーン移動が出来る。

スポンサーリンク
スポンサーリンク
  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク
スポンサーリンク