ProgressionのCommandクラスを使いこなしたいよ(その1)
niumさんのご好意でkazekotoba.をProgression Frameworkの 制作事例に掲載していただきました!嬉しいやら、恥ずかしいやら、申し訳ないやら…。
そんなわけで、niumさんやteracoやSpark Project いうコミュニティの存在があって、今回なんとか作品を完成させることができたわけですが、実際にProgressionを使ってみて、個人的に最も萌え度が高く、かつ難所のひとつでもあったCommandクラスについてのお話なぞを、僕なりに噛み砕いて綴ってみたいと思いますので、ヨロシクお願いします。
以下は今回のプロジェクトで僕が実際に書いたものの抜粋で、一番最初に移動するSceneObjectのコードの一部です。「SceneObjectとか"移動する"とかいきなり語りだすなよ」という方は、Progressionのチュートリアルの「クラスベースでの制作スタイル」を読んでみてください。サンプルキットも用意されているので、とりあえず手を動かしてみるといいかと思います。
protected override function _onLoad():void {
addCommand(
// パーティクル描画用のカンバスをディスプレイリストに追加
new AddChild(progression.container, canvas),
// 個別記事ページの表示の場合、イントロを省略する処理
new IfElse(
function():Boolean {
return Boolean(!postID); // URL末尾に投稿記事IDがないかチェック
},
new Func(this, playIntro), // イントロ有
new Trace("イントロを省略") // イントロ無
),
// DBから記事データを取得
new LoadPostData(model, "getPost", postID),
// マウスジェスチャーナビを、深度指定してディスプレイリストに追加
new AddChildAt(progression.container, gestureNav, 100)
);
}
突っ込みどころ満載のコードだと思いますが、僕なりの解説をば。
まずCommandクラスの使いどころですが、おそらく最も基本的なカタチとしては、上記のようにSceneObjectやjp.progression.castsパッケージ内にあるCastほにゃららクラスにて、addCommandメソッドのパラメータにCommandインスタンスを渡すような使い方ではないかと思います。他にも色々便利な使い方がありそうな匂いがぷんぷん漂っているのですが、いまのところは僕の定番の使い方としてはコレが基本です。
ここでオーバーライドしているSceneObjectの_onLoadメソッドは、progressionがこのSceneObjectへとシーン移動をし、到達した瞬間にトリガーされます。このタイミングで実行したい諸々の命令(Command)を、addCommandメソッドを使用し、予め登録しておく感じです。
addCommandでCommandインスタンスを渡すと言いましたが、実際にはCommandクラスは直接インスタンス化することはできませんので、厳密に言うと、jp.progression.commandsパッケージに用意されている一連のCommandクラスのサブクラス、もしくはCommandクラスを継承したユーザ定義のカスタムコマンドクラスを使用します。
今回の例で言うと、 AddChild、AddChildAt、IfElse、Func、Traceは、Progression組み込みのCommandサブクラスで、LoadPostDataは自作したカスタムコマンドクラスです。commandsパッケージには、イージング機能を実行するDoTweenerや、シーン移動を実行するGoto等、他にも便利なコマンドがたくさんありますので、コマンド処理でどういったことができるのかを知るためにも、予め目を通しておくことをお勧めいたします。
上記コードは、まずcanvasというカスタムクラスのインスタンスを表示し、イントロ用のページを表示するかどうかを、条件分岐に応じて処理。その後任意の投稿記事情報をデータベースから取得します。なお、ここではpostIDの値を取得するメソッドの詳細は掲載していませんが、これはExternalInterfaceでJavaScriptを呼び出し、ブラウザのURLから、投稿記事のIDを取得しています。
ここまでの一連の命令は順次実行されますが、最後のDBからのデータ取得については、結果が返ってくるまで、次の命令を実行しないようになっています。そしてデータを取得した時点で、ナビゲーションを表示するコマンドを実行しています。
さて、かなり大雑把で中途半端な説明でしたが、Commandクラスの概要については、ざっくりとでも分かっていただけましたでしょうか?実のところ、僕もざっくりとしか分かってません。そんなわけで、このコードも動作してはいるものの、条件分岐や非同期処理の扱い等に関して、本当にコレでいいのかイマイチ自信がない点がいくつかあります。ということで、次回はそのことについて、もう少し突っ込んでエントリーしようと思います。

解説ありがとうございます!
(こっそりチュートリアルにもリンクを追加しました)
外部ファイルの読み込みは、あまりベーシックなスタイルを提案できていないところなんですが、
自分で使っていて一番しっくりくるのは、Func コマンドを使った方法ですねー。
new Func( null, loader.load, null, 0, loader.contentLoaderInfo, Event.COMPLETE )
のようにすると、loader インスタンスの load() メソッドを実行した上で、contentLoaderInfo が Event.COMPLETE を発行するまで処理を停止してくれるので、
コマンドの途中で別の処理をして戻ってくる・・・ようなコードはすごく書きやすいと思います。
また、外部ファイルの場合には、
new LoadURL( new URLRequest( "hoge.xml" ) )
.after( null, function():void {
trace( this.data );
} );
のようにすれば、読み込んだ内容を参照できたりします。
この辺の外部ファイルの扱いについては、今度力を入れて開発していく予定ですので、何か使いづらい点などがありましたら、フォーラムやブログに書き込んで頂ければ対応しますね!
うは、知らなかった。
外部画像を読み込む処理も、
わざわざカスタムコマンドを作ってしまいました。
afterとかbeforeの使いどころも、
よく分からなかったのですが、なるほどー!
僕のイケテナイ例も含めて、
またエントリーさせて頂きますので、
宜しくお願いします。