swf から CreateJS-Haxe用 extern クラスを生成するアプリ制作開始
先日 Toolkit for CreateJS の出力ファイルを Haxe クラスに変換するアプリを公開しました。しかし、メンテナンスの難さがあったり クラス構造がイマイチであったりと、やや問題が残る状況でもあります。
Toolkit for CreateJS の出力ファイルを Haxe クラスに変換するアプリ公開
http://www.dango-itimi.com/blog/archives/2013/001167.html
色々考えた結果、別途アプリケーションを制作し、問題解決 + 更なる開発のし易さ向上を図ることにしました。
アプリケーション内容
swf から CreateJS-Haxe用 extern クラスを生成するアプリケーションを制作します。大まかな内容としましては以下の手順を採ります。
swf から Haxe 用 extern クラス生成
以下の URL 内情報を参考に、swf から hx クラスの生成を行います。これは haxe の機能となります。
Haxe: swcを使う/エクスポートする
http://haxe.org/manual/swc
swf の構造がそのまま Haxe クラスに変換され、Flash CS ステージ上に配置したインスタンス名等もきちんとクラスフィールドプロパティとして変換されます。
swf から Haxe クラスを生成するコマンド実行は Flash のパブリッシュ後に都度行うのは面倒なので、Windows の場合 bat ファイル経由で生成予定のアプリケーションから実行可能にしたいと思います。
生成された extern クラス内 Flash 用 API を CreateJS-Haxe 用 API に変換
swf から生成された Haxe クラス群は Flash 用 API を利用した形として変換されるため、このままだと Haxe javascript 用プロジェクトからは利用できません。よって、生成されたクラス内の flash.display.MovieClip といった記述を createjs.easeljs.MovieClip といった文字列に書き換え、別途 Haxe クラス群を出力します。
@:native メタデータの利用
Toolkit for CreateJS で出力された js ファイル内 各クラスのパッケージ構造と、swf から出力した Haxe extern クラスのパッケージ構造が異なるため、@:native メタデータを利用して整合性をとります。
総合すると例えば以下の様な変換を行うことになります。
swf から出力された Haxe extern クラス例
package shooting.shot; extern class View extends flash.display.MovieClip, implements Dynamic { function new() : Void; }
アプリケーションによる変換後のクラス
package shooting.shot; @:native("lib.shootingshotView") extern class View extends createjs.easeljs.MovieClip, implements Dynamic{ }
html5 + Flash の同時開発
今回制作するアプリでは、Haxe の以下の点を重要としました。
・異なるプラットフォーム用クラスでも 共通する記述部分の利用には条件付きコンパイルの指定は不要
Haxe ではさまざまなプラットフォーム向けソースコードを 一つのクラスファイル内に記述する事が可能です。例えば html5 用 javascript API の記述と Flash 用 ActionScript API の記述を同一のソースコード内に混在させる事ができます。
Haxe: 条件付きコンパイル
http://haxe.org/ref/conditionals
コメントアウト + if文 のような物を用いて、それぞれのプラットフォーム向けのソースコードを記述します。
ここで、当アプリケーションでの変換処理を利用する事により 条件付きコンパイル記述をそこそこ減らすことが可能になります。
例えば、以下の様なファイルディレクトリ構成があったとします。
├ src/ │ └ Main.hx │ ├ src_flash/ │ └ AAA.hx │ └ src_js/ └ AAA.hx
src_flash/AAA.hx は swf から haxe の機能により出力され、当アプリケーションを用いることで src_flash/AAA.hx から src_js/AAA.hx に変換生成されます。
src_flash/AAA.hx クラスは flash.display.MovieClip を親に、src_js/AAA.hx クラスは createjs.easeljs.MovieClip を親に持ちます。(説明例なので実際に出力されるクラスの内容とは少々異なります。)
src_flash/AAA.hx
package; class AAA extends flash.display.MovieClip{ }
src_js/AAA.hx
package; class AAA extends createjs.easeljs.MovieClip{ }
Main.hx の内容は以下のようになります。Flash 用プロジェクトからは、src_flash ディレクトリにクラスパスを、javascript 用プロジェクトからは src_js ディレクトリにクラスパスを追加する事で、Main.hx のコンパイルが可能となります。
package; class Main { private var aaa:AAA; public static function main() { new Main(); } public function new(){ #if flash aaa = new AAA(); #elseif js aaa = new AAA("", 0, false, {}); #end } private function move(){ aaa.x += 1; } }
createjs.easeljs.MovieClip のコンストラクタには引数指定が必要なので、Main.new メソッドでは条件付きコンパイルを利用しています。(引数指定は本当は不要かもしれませんが、ここではその説明は略します。)
一方 Main.move メソッドでは条件付きコンパイル記述の必要はありません。flash.display.MovieClip と createjs.easeljs.MovieClip には共通のプロパティ MovieClip.x が存在するからです。EaselJS と AS3 のクラス構造は似ているのが何ともありがたい点です。また、生成部分のみ条件付きコンパイル指定を行い、処理が複雑に行われるロジック部分では条件付きコンパイル指定を省くことができるのは結構なメリットと言えます。
当アプリケーションが完成したら、一つの fla ファイルから、より少ない Haxe ソースコードで、html5 canvas 物と Flash(swf or AIR) の同時開発が行えるようになりそうです。