Progression FrameworkのFuncコマンド+loader.loadでロード失敗すると、もうどうしようもない疑惑
Progression Frameworkのコマンド使ってみよう大会継続中だが、今回はLoaderクラスとFuncコマンドを使ってロード完了待ちをしようと言うテクニックと、発生した問題点について述べたいと思う。
Funcコマンドを使った方法は、
こちらを参考にしてみた。
■Funcコマンドでデータ読み込み
さて、Funcコマンドを使った読み込みだが、このような感じになる。
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が間違ってたり、その他の理由で画像が読み込めない状況になったらどうなるか?
こうなる。
簡単に言うと、「何も出来なくなる」。
画像は勿論表示されないし、次のシーンに移動もしない。
それどころか、他のボタンを押しても何も起きない。処理が完全に停止し、どうしようもなくなるようなのだ。
何故か!?
それはこれ。
Funcに指定できる、「あるオブジェクトがあるイベントを送出するまで、処理を停止する」機能のせいだ。
この例の場合だと、loader.contentLoaderInfoから画像読み込みが完了したことを示すEvent.COMPLETEが送出されるまで、コマンドは処理を停止し、待ち続ける。
が、読み込み失敗時には、その原因に応じてIOErrorEvent.IO_ERRORやSecurityErrorEvent.SECURITY_ERRORなどが送出され、Event.COMPLETEが送出されないままで読み込みは終了する。
で、そのままFuncコマンドはずーっと待ちぼうけし続け、以降のコマンドは全く実行されないと言うわけだ。
さらに、addCommandで一気にコマンドを追加すると、全部が終了するまで他の処理が行われないらしい。前回のエントリで書いた並列実行と直列実行のサンプルでも、直列実行時に一番上のボタン0を押しても何も起きない。すべてのボタンが出終わってからでないと、ボタンの動作が無視されるようなのだ。
■更なる悲劇が!
さて、ではエラー時はどうすればいいのか?
取り敢えず、エラーイベントを拾ったらおとなしく他のシーンに移ってはどうか?
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メソッド内。
今回のコード例だと、コードがあるシーンはルートの子で、行き先は自分の子、つまりルートの孫になる。
なので、エラー時にルートに移動するとどうなるか?
- 画像読み込み(
Func)開始 - IOエラー発生。ルートへ移動
- シーンが移動し、画像読み込み用の
Funcコマンド停止 - 画像表示(
AddChild)開始 - シーン移動(ルートの子の子への
Goto)開始 - ルート→孫への移動の過程で、画像読み込みシーンの
_onLoad実行 - 1.に戻る
このように無限ループに陥ってしまう。
ミソは、シーンを移動してもFuncが終わるだけで、後続のコマンドが実行されると言う点。
なので、画像読み込みは_onInitに書かないとダメ。
まぁ、この辺りはシーン移動のパズルだな。
ちゃんと理解して上手く考えないと、ヒドイ目に逢いますよと言う話。プログラムの世界じゃよくある事だ。
と言うわけで、_onInitにaddCommandを移したバージョンはこちら。
画像読み込み失敗でも、ちゃんとシーン移動が出来る。




