Starling Framework を使ってみた(その1)


Starling FramworkはStage3D上で2D描画する為のフレームワークです。
GPU描画でのサクサク動作を期待して、実際にサンプル作ってみて体感してみました。

(注:音が鳴ります▲)

上記のサンプルは鮫のキャラクタを操作して10秒以内に魚を70匹ゲットするという内容ですが、大量のオブジェクトを描画する際にどれぐらいパフォーマンスがでるのか、加えてパーティクル を表示するとどれぐらい負荷になるのか、というあたりを確認してみました。

開発Tips


今回のサンプルコンテンツは横スクロール型で大量に湧いてくるアイテムをプレイヤーがゲットするという、下記参考情報でご紹介している「Hungry Hero」とほぼ同じ内容ですので、詳細な作り方はそちらのビデオチュートリアルGitHubをご参照ください。ここでは便利だなーと思った機能やTipsについてご紹介します。

  1. AssetManagerを使う
  2. AssetManagerはコンテンツで利用する素材をまとめて管理/アクセスする事ができる機能(Starling 1.3)です。
    以下は、AssetManagerを使わずに、埋め込んだスプライトシート画像とその表示設定XMLの2つの素材を、
    まとめてTextureAtlasクラスで管理してアニメーション表示MovieClipに利用する例です。

    [EmbeddedAssets Class]
    public class EmbeddedAssets{
    [Embed(source=”atlas.xml”, mimeType=”application/octet-stream”)]
    public static const AtlasXml:Class;
    [Embed(source=”AtlasIMG.png”)]
    public static const AtlasIMG:Class;
    }
    _
    [Main.as]
    var texture:Texture = Texture.fromBitmap(new EmbeddedAssets.AtlasIMG());
    var xml:XML = XML(new EmbeddedAssets.AtlasXml());
    var atlas:TextureAtlas = new TextureAtlas(texture, xml);
    var movie:MovieClip = new MovieClip(atlas.getTextures(“flight_”));

    上記の例を、AssetMangerを利用すると以下のように使う事ができます。
    まずAssetManagerに利用する素材クラスをキューに追加し(各種素材のファイルパスでもOK)、
    キューの処理完了後にAssetManagerからTextureAtlasを取得し、MovieClipに利用しています。

    [Main.as]
    var assets:AssetManager = new AssetManager();
    assets.enqueue(EmbeddedAssets);
    assets.loadQueue(function(ratio:Number):void{
    if (ratio == 1.0){
    var movie:MovieClip = new MovieClip(assets.getTextureAtlas(“AtlasIMG”).getTextures(“flight_”));
    }
    });

    AssetManagerはpng, jpg, atf, mp3, xml, fntファイルをサポートしているので、利用する各種素材をAssetManagerに追加しておけば、アクセスは一箇所から、かつ呼び出しも簡単になって便利ですね。
    ちなみに、AssetManagerでTextureAtlasを読込む際は、画像ファイル名とクラス名を同じにしておく必要があるそうです。(参考:「Error in new Asset Manager – TextureAtlas.as – line 87」)

  3. Starling.juggler.tweenを使う
  4. StarlingでもTweenクラスが用意されているので使ってみました。現在のところ2種類の書き方があるようです。
    まず従来からあるTweenインスタンス生成+設定+jugglerへの追加を行う方法です。

    //生成
    var tween:Tween = new Tween(object, 2.0, Transitions.EASE_IN_OUT);
    //設定
    tween.animate(“x”, object.x + 50);
    //再生
    Starling.juggler.add(tween);

    次にStarling.juggler.tweenを使う場合ですが、直接jugglerへの追加を行う方法になります。(Starling 1.3)

    Starling.juggler.tween(object, 2.0, {
    transition: Transitions.EASE_IN_OUT,
    x: 50 // -> tween.animate(“x”, object.x + 50)
    });

    コード量は然程変わりませんが、Starling.juggler.tweenの利点としては、
    jugglerの内部でtweenインスタンスをプールして再利用してくれるので、
    ガベージコレクションの実行を抑制できる点かと思います。

  5. Statsを使う
  6. FPSとアプリケーションメモリと描画数を表示するための機能です。
    今回のパフォーマンスの具合を見るのも、この機能を利用しています。

    Starling.current.showStats = true;
    Starling.current.showStatsAt(“left”,”top”,2);

    メモリはFlashPlayer/AIRのSystem.totalMemoryを参照しているそうです。(参考:「What mem stats mean」)
    描画数に関しては「how to find what is doing the draw calls?」のスレッドが参考になるかと。出来るだけ1つのtexture/atlasに素材を集約すると描画数を減らせたり、逆にalpha/color/BlendModeの値がバラバラだったりすると増えるようです。(参考:「draw calls」)

パフォーマンスはどんな感じ?


サンプルコンテンツのFPSがPCとiPhone/iPadでどれぐらい出ているかをチェックしました。(パーティクルなし/あり)

  • WinXP(Corei7/8G RAM): 60FPS/ 60FPS
  • iPad 4th: 60~40FPS / 60~40FPS
  • iPone 5: 60~40FPS / 60~40FPS

パーティクルありだと○FPSほど落ちるよ。今回の例ではあまり変化なしでした。パーティクルについては次回「Starling Framework を使ってみた(その2)」でご紹介します。

さらに魚のみを大量に表示する検証コンテンツをStarlingバージョンと通常のFlashバージョンを作って比べてみました。(PC版のみ)この魚はTweenで画面端から端まで移動を終了時まで繰り返しています。さらに、魚の数は徐々に増加させていきます。アニメ付きの魚MovieClipを大量(200匹)に表示する際にどれぐらいのFPS(デフォルト60)が出るのかを確認しました。

[Starling版]                 [通常Flash版(wmode:指定なし)]

  • Starling版:200匹まで60FPS前後
  • 通常版:50匹で30FPS、100匹で20FPS、200匹で15FPS前後

上記の結果からもStarlingが安定してパフォーマンスが良いことが分かりますね。とは言え、Starlingにもパフォーマンスチューニングが必要になってくるので、以下の参考URLに書かれてるTipsの概要をご紹介します。
(参考:「Performance Optimization」)

  1. パフォーマンスを確認する際は、リリースビルドで確認する。(特にiOS。デバッグビルド時の「標準」でのビルドはNG!)
  2. Loaderを使って画像読む際はデコード処理を非同期で行う設定で利用する。デフォルト設定(同期デコード)のままだと、Textureで利用する時にデコード処理が走るので、アプリ動作をブロックしてしまうから。(非同期デコードにしておけば、Completeイベント前にデコードを別スレッドで行う)

    loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD

    (参考:「ビットマップイメージの非同期デコード」)

  3. テクスチャの状態変化は最小限にとどめる(BlendMode/Smooth/RpeatMode/色・透明度の変化など)
  4. 各種テクスチャはTextureAtlasを出来るだけ利用して、出来るだけ1箇所にマトメると描画(draw call)が少なく済む。
  5. 複数のTextureAtlasを利用する場合、描画する順番も考慮してまとめる必要がある。(詳細は「Performance Optimization」のTexture Atlasの項目をご確認ください。図解で分かりやすいです)
  6. 位置が変化しないオブジェクトは、StarlingのSpriteクラスのflatten()を使って固定化すると、フレームごとにGPUに新たにアップロードせずに描画することができる。
  7. テキスト表示にはビットマップフォントの利用がおススメ。EmbedしたTrueTypeフォントを利用すると、一旦スナップショットを撮ってGPUに送っているので、その分処理が多くなる。なので、特に頻繁に更新されるテキストはビットマップフォントの利用がおススメ。(参考:「Episode 10: Text and Fonts」)
  8. 透明度が不要なテクスチャはBlendMode.NONEとする
  9. For文などでなんども”width/height”を参照するのは避ける
  10. タッチ操作が必要ないSpriteは、touchable = falseとする
  11. 新しいEventモデル(dispatchEventWith)を利用する。Eventオブジェクトをプールして再利用できるので、ガベージコレクションの実行を抑制できる

参考情報

  • 初めてStarlingを使う上で参考になったのは公式Wikiの「The Starling Manual」で、
    このページを読み進めると、Starlingの使い方が掴めるんじゃないでしょうか。
  • また、今回作ったサンプルゲームっぽいものを作る上で参考になったのが、
    公式Wikiで紹介されている「Hungry Hero」のビデオチュートリアルGitHubに公開されているコードです。
  • この2つと、ダウンロードしたSDKについてるサンプルコードを見ながら進めていくと、
    どんな風に実装すると良いのかお手本になるので、とても参考になりました。