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

このエントリをはてなブックマークに追加このエントリをはてなブックマークに追加このエントリをdel.icio.usに追加このエントリをLivedoor Clipに追加このエントリをLivedoor Clipに追加このエントリをYahoo!ブックマークに追加このエントリをFC2ブックマークに追加このエントリをNifty Clipに追加このエントリをPOOKMARK. Airlinesに追加このエントリをBuzzurl(バザール)に追加このエントリをBuzzurl(バザール)に追加このエントリをChoixに追加このエントリをnewsingに追加このエントリをkwoutに追加
2008年4月11日 金曜日0:45:19

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

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

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

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

var loader:CastLoader = new CastLoader();
loader.contentLoaderInfo..addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {
    trace("読み込み失敗(IO):", sceneId, url, e);
});
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:SecurityErrorEvent):void {
    trace("読み込み失敗(SEC):", sceneId, url,e);
});
addCommand(
    new Func(null, loader.load, [new URLRequest("image.jpg")], 0,
             loader.contentLoaderInfo, Event.COMPLETE),
    new AddChild(progression.container , loader , true),
    new Goto(children[0].sceneId)
);

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

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

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

何故か!?
それはこれ。

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を押しても何も起きない。すべてのボタンが出終わってからでないと、ボタンの動作が無視されるようなのだ。

■更なる悲劇が!

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

var loader:CastLoader = new CastLoader();
loader.contentLoaderInfo..addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {
    trace("読み込み失敗(IO):", sceneId, url, e);
    new Goto(progression.root.sceneId).execute();
});
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:SecurityErrorEvent):void {
    trace("読み込み失敗(SEC):", sceneId, url,e);
});
addCommand(
    new Func(null, loader.load, [new URLRequest("image.jpg")], 0,
             loader.contentLoaderInfo, Event.COMPLETE),
    new AddChild(progression.container , loader , true),
    new Goto(children[0].sceneId)
);

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




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

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

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

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

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

トラックバック URL :

コメントをどうぞ

HTML convert time: 0.649 sec.