ゼットコードログ

コード的な何かを書いていきます。

OpenFL アプリの画面をPhotoshopとFlash Professionalで作る

Flashで作ったswfファイルを画面として取り込んで、表示することができます。

これだけだとAdobe AIRと変わらないですが、OpenFLはswfをインプットにしてコンパイルの段階で 各プラットフォーム用のプログラムを生成しているみたいです。これにより、AIRと比較した場合により高速に動作するし、ランタイムも必要ないのでプログラムのファイルサイズが小さくてすみます。

各パーツはSpriteやMovieClipとして取得してイベントや設定の変更を適宜実行することができます。

ということを試すためにサンプルでクイズアプリを作ってみました。デザインはご愛嬌。機能もペラペラです。

f:id:z-ohnami:20140523011504p:plain

工程はこんな感じで進めることができます。

  1. PhotoShopで画面をデザインし、PSDファイルを作る
  2. PSDファイルをFlash Professionalで取り込んで、各パーツをシンボル化し、リンケージとインスタンス名を設定
  3. Flash ProfessionalでパブリッシュしたSWFファイルをOpenFLのプロジェクトに取り込む
  4. Haxeでコードを書いて開発していく

とてもよいのはPhotoshopで画面デザインができるということ。PhotoShopの成果をほぼそのままダイレクトにアプリまでもっていけます。 1をデザイナーさんにやってもらって、それ以降の工程をプログラマとかエンジニアとかがやっていけばOK。

このデザイナーさんとの協業の部分がヘタすると従来のFlashベースの開発よりもとてもシームレスにできそうな予感。

あとは製品リリースレベルの複雑なデザインがきた場合に 果たしてこの工程がそのまま使えて、OpenFLが耐えられるかどうか。これは実際にやってみないとわからないですね。

プロジェクト的には swfとlayoutというライブラリを使います。 project.xmlに次のように設定しましょう。

<haxelib name="openfl" />
<haxelib name="actuate" />
<haxelib name="swf" />
<haxelib name="layout" />

あとは自分で作ったswfファイルもライブラリとして指定しておきます。

<library path="Assets/ui.swf" />

アプリのソース内ではswfのファイル名とリンケージを指定してswfファイルにアクセスします。 今回はLayoutというリンケージをflaファイル内で指定しています。その配下のインスタンスはgetChildName関数で名前を指定すれば取得できて、そこから先はプログラミングの世界です。

Assets.loadLibrary ("ui", function (_) {

    var layout = Assets.getMovieClip ("ui:Layout");
    addChild (layout);

    layoutManager = new LayoutManager (640, 960);

    layoutManager.addItem (new LayoutItem (layout.getChildByName ("Button1"), LayoutType.STRETCH, LayoutType.STRETCH, false, false));
    layoutManager.addItem (new LayoutItem (layout.getChildByName ("Button2"), LayoutType.STRETCH, LayoutType.STRETCH, false, false));
    layoutManager.addItem (new LayoutItem (layout.getChildByName ("Button3"), LayoutType.STRETCH, LayoutType.STRETCH, false, false));

    layoutManager.resize (stage.stageWidth, stage.stageHeight);
    stage.addEventListener (Event.RESIZE, stage_onResize);

    _button1 = cast(layout.getChildByName ("Button1"),Sprite);
    _button1.addEventListener(MouseEvent.CLICK,function(event:MouseEvent):Void { checkAnswer(0); });

ソースコード全体はこちら。psdとflaファイルも付いてるよ。

z-ohnami/OpenFLQuizSample · GitHub

swfを更新した場合はlimeでビルドする際に-cleanオプションを使ったほうがいいみたい。 じゃないと、更新が反映されないことがあるようです。これでしばらくハマっていた・・・

OpenFLのプログラムをiOSの実機で動かす

androidのときのようにsetupコマンドを最初にやるのかと思ったらそうではないみたい。

YouもXcode入れるかい?みたいな質問がでてきてそれで終わっちゃう。

//これはやっても意味なし!!
$ lime setup ios

手順

  1. Xcodeのインストール
  2. 証明書ファイルをセット
  3. iTunes経由でプロビジョニングプロファイルを実機に入れる
  4. lime test ios
  5. 動き出す

Xcodeは普通にAppStoreからダウンロードしてインストールすればOKです。

その後、開発用の証明書を作成して project.xml に次のように設定を入れておきます。

この例だとios_dev.p12が証明書のファイル名で、一緒にパスワードも書いておけます。

<certificate path="ios_dev.p12" password="abcdef" if="ios"/>

iOS実機の場合はさらにプロビジョニングプロファイルをiTunes経由で先に仕込んでおきます。 私はこれに気が付かなくて小一時間悩みました。

あとは他のプラットフォームと同じようにlime test ios で動作すると思います。

$ lime test ios

Androidと違ってシュミレーターの起動速度が速いので、デバッグ時はこちらを使うのがいいかもしれません。 ある程度出来上がったら、実機で確認というパターンでしょうか。

$ lime test ios -simulator

OpenFL XMLのデータを読み取る

次のような流れでやってみます。

  1. 天気予報のXML情報を取得
  2. XMLの情報を解析
  3. 画面に表示する

XMLは天気情報をXMLで提供してくれているところから取得してみます。

気象庁の天気予報情報を XML で配信 - drk7jp

var requestUrl:String = "http://www.drk7.jp/weather/xml/13.xml";

XMLHaxehaxe.xml.Fastを使うと楽です。

var fastXml = new haxe.xml.Fast(xml);

Fastが大分サポートしてくれるけれども、それでも、for文とif文の連発になってしまう・・ このあたりはActionScriptのほうがもっと簡単に書けるなぁ。属性でフィルタリングしたりできたし。

Android向けにビルドする場合はproject.xmlパーミッションを設定しておきます。

<android permission="android.permission.INTERNET"/>

Parse XML

f:id:z-ohnami:20140506002638p:plain

OpenFL 日本語のフォントを使う

TextFormatでフォントファイルを設定します。

まずは、projet.xmlのリソースファイルでフォントの場所を指定しておきます。

<assets path="assets/font" rename="font" />

で、コードの中では Assets.getFontでフォントを取得して

var font = Assets.getFont ("font/misaki_mincho.ttf");

TextFormatでフォントを指定し

format.font = font.fontName;

TextFieldでformatを紐付け。これでOK。改行は'\n'でいけそう。

_text.text = 'z.ohnamiです。\nIs there any problem ?';
_text.setTextFormat(format);

またはdefaultTextFormatを使う。 text.defaultTextFormat = format; text.text = 'z.ohnamiです。\nIs there any problem ?';

重要なのは順番でtextプロパティを設定した後にsetTextFormatしないとフォントなどTextFormatに指定した内容が反映されないです。 逆にdefaultTextFormatはtextプロパティ設定の前に指定しておきます。

use Font Resource

フォントはこちらのファイルを使わせていただきました。謝。

8×8ドット日本語フォント「美咲フォント」

OpenFL サーバーのAPIを実行して値を取得する

画像の次は文字列です。 apiを叩いて、データを取得する。よくある日常です。

文字列をJSON形式としてパースしています。

var data:String = cast(event.currentTarget.data, String);
var user = Json.parse(data);

var text:TextField = new TextField();
text.text = user.name;

get API Data from server

OpenFL サーバーから画像を取得する

ローカルではなくて、サーバーから動的に画像を取得して表示したい。 とてもよくあることです。

Loaderクラスを使ってみましょう。 読み込み完了時に発動する関数をセットして、その後に画像表示処理を書いていきます。

var requestUrl:String = "http://192.168.24.24/img/hana.jpg";

var loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
loader.load(new URLRequest(requestUrl));

で、lime test flashだと画像が表示されない・・ html5でビルドすると普通に表示された。なぜ?

最初、セキュリティ設定がproject.xml にあって、外との通信を弾いているのかと思ったけどそうでもないっぽい。 これは実機で動作するか確認したほうがいいっすね。

オフィシャルのAPI一覧を見るとLoaderクラスは「Available on all platforms」とあるが・・

display Image from web server

OpenFL イベント発生時にデータも送る

DataEvent というのがあって、それを使います。

データは文字列に変換しておきます。 最初、cast(value,String) というのがいいのかと思ったら、 コンパイルエラーが出たので使ってないです。

_rect.dispatchEvent(new DataEvent(MyRect.EVENT_MOVE,false,false,Std.string(getNextColor())));

受ける側はこのように。コールバック関数の引数の中に入ってやってきます。

private function onReceiveEvent(event:DataEvent):Void
{
    trace(event.data);
    x += 10;
    y += 10;
    drawRect(Std.parseInt(event.data));
}

Event with data