Flash でアニメーションと言えばやはり MovieClip ですが、Starling にも MovieClip というクラスがあります。もちろんアニメーション用のクラスです。
前回少し触れましたが、Starling で画面に表示できるのは、ビットマップ画像か色を指定した矩形です。そのため、名前は同じ MovieClip でも、Starling の MovieClip は、フレーム毎に割り当てられたビットマップを表示するクラスとなっています。
また、Starling の MovieClip には子オブジェクトを管理したり、フレームにスクリプトを持つ機能がありません。この点も Flash Player の MovieClip とは大きく異なります。
(Starling では、表示リストの管理は Sprite の担当です。一方、MovieClip は Image クラスにタイムライン機能を足した Image のサブクラスです。MovieClip が Sprite のサブクラスである Flash Player とは異なり、両者の役割はほとんど被りません。)
スプライトシートとテクスチャアトラス
MovieClip の各フレームを表示する際、GPU では、表示するフレームに割り当てられたテクスチャが、シェーダから利用できるよう準備が行われます。その際、テクスチャが、フレーム毎に物理的に異なるビットマップファイルだったりすると、フレームを進めるたびにテクスチャの切り替えが発生します。
テクスチャの切り替え処理には当然時間がかかります。また、テクスチャの GPU へのアップロードが必要になると、さらにオーバーヘッドは増します。
一般的に、この問題を回避するため、各フレームのテクスチャを 1 つのファイルにまとめた物を用意します。これをスプライトシートと呼びます。
下の図は、Starling のサンプルに含まれるスプライトシートの 1 部を切り出したものです。
複数フレーム分のテクスチャが 1 つのファイルになっていると、GPU にとっては使う場所を変えるだけで、テクスチャ自体を切り替えることなく、描画処理が行えます。そのため高速にフレームを更新できます。
また、Stage3D が扱うテクスチャの幅は 2 の階乗というルールのため、それ以外の幅のテクスチャでは、Starling 内部で余分な事前処理が発生します。しかし、スプライトシートの場合は、表示されるテクスチャが、より大きなテクスチャ (スプライトシート) の 1 部となるため、個々のテクスチャの幅に頭を悩ませる必要がなくなります。
この最適化をさらに 1 歩進めたのが、テクスチャアトラスです。テクスチャアトラスは複数のスプライトシートを 1 つのファイルにまとめたものです。同時に複数のアニメーションを再生する場合は特に有効です。
テクスチャアトラスを作るには、次期バージョンの Flash Professional CS6 でサポートされるらしい、ベクターアニメーションのスプライトシートへの書き出し機能を待つか、Texture Packer 等のツールを利用することになります。
テクスチャアトラスの読み込み
テクスチャアトラスを使うと、フレームごとに、それぞれ、テクスチャアトラス内のどの領域を表示するか? という情報が必要になってきます。
そのため、以下のような形式で各フレームのテクスチャ情報を指定することになっています。ツールを使ってテクスチャアトラスを生成する場合は、このような XML ファイルも同時に生成されると思います。
<TextureAtlas imagePath='atlas.png'> <SubTexture name='walk_0' x='0' y='0' height='150.5' width='87.0'/> <SubTexture name='walk_1' x='88' y='0' height='150.5' width='87.0'/> <SubTexture name='walk_2' x='176' y='0' height='150.5' width='87.0'/> <SubTexture name='walk_3' x='264' y='0' height='150.5' width='87.0'/> </TextureAtlas>
TextureAtlas タグの imagePath 属性は、テクスチャアトラスのファイル名です。この場合は、atlas.png です。
SubTexutre タグの name 属性は、アニメーションの識別名の後に、フレームの番号を追加したものです。残りの x, y, height, width で、テクスチャとして使う領域を指定します。
(実際に SubTexture というテクスチャの一部を扱うためのクラスがあります)
さて、テクスチャアトラスの準備ができたら、以下のようにプログラムに埋め込みます。
[Embed(source = "atlas.png")] private static const MyBitmap:Class; [Embed(source="atlas.xml", mimeType="application/octet-stream")] private static const MyXml:Class;
これらの情報は TextureAtlas というクラスでまとめて管理します。テクスチャアトラス (PNG ファイル) は、一旦 Texture クラスに読み込んでから、XML ファイルと一緒に、TextureAtras のコンストラクタに渡します。
TextureAtlas のオブジェクトからは、識別名を指定して、Texture の (実際には SubTexture の) ベクターを取得できます。その際に使用するメソッドは getTextures() です。
import starling.textures.TextureAtlas; private function onAddedToStage(e:Event):void { // テクスチャアトラスの読み込み var myTexture:Texture = Texture.fromBitmap(new MyBitmap()); // テクスチャアトラス内の領域情報の読み込み var myXml:XML = XML(new MyXml()); // TextureAtlasのインスタンス生成 var myTextureAtlas:TextureAtlas = new TextureAtlas(myTexture, myXml); // "walk_"を識別名として持つTextureのベクター生成 var frames:Vector.<Texture> = myTextureAtlas.getTextures("walk_"); ...この先は下に続く }
ベクター内の最初のテクスチャの大きさが、アニメーションの表示領域を決定します。
アニメーションの再生
ここまでくれば、あとは MovieClip のインスタンスを生成するだけです。MovieClip コンストラクタの引数には、上で取得したテクスチャのベクターを指定します
import starling.display.MovieClip; private var myMovieClip:MovieClip; private function onAddedToStage(e:Event):void { ...上からの続き // MovieClipオブジェクトの生成 myMovieClip = new MovieClip(frames); // アニメーション再生開始 Starling.juggler.add(myMovieClip); addChild(myMovieClip); }
お気づきのように、MovieClip の再生にも Tween と同様 Juggler を使います。MovieClip も IAnimatable のサブクラスです。
Juggler に MovieClip を追加すると再生が開始されます。再生を制御するため、以下の 3 つのメソッドが用意されています。
myMovieClip.play(); myMovieClip.pause(); myMovieClip.stop();
pause() の後に play() を呼んだ場合は続きから再生されますが、stop() の後に play() を呼ぶと最初から再生されます。
標準では、アニメーションは繰り返し再生されます。この設定は loop 属性の設定により変えることができます。再生中かどうかは isPlaying 属性で調べられます。
アニメーションが最後まで再生されると movieComplete イベントが発生します。再生が完了したら次の処理に移りたいという場合に使えそうです。
myMovieClip.addEventListener(Event.MOVIE_COMPLETED, onMovieComplete);
アニメーションが繰り返し再生されるときは、再生が完了するたびに movieComplete イベントが発生します。
MovieClip の親の Sprite が Stage から削除されたら、MovieClip は再生を中止しなければなりません。そこで、以下のような記述を追加しておきます。
addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage); private function onRemovedFromStage(event:Event):void { Starling.juggler.remove(myMovieClip); }
Juggler の remove() メソッドは MovieClip だけでなく Tween も削除できます。
ちょっと変わった MovieClip の使い方
MovieClip のコンストラクタの第 2 引数に、任意のフレームレートを指定することができます。こんな感じです。
// 40 fpsを指定 myMovieClip = new MovieClip(frames, 40);
MovieClip ごとに、異なるフレームレートの指定が可能です。
再生中のフレームレートは fps 属性から取得できます。また、fps 属性に値を設定することにより、フレームレートを変更することもできます。
それから、任意のフレームに対して、個別の再生時間を指定することもできます。下は、5 フレーム目を 2 秒間再生するよう設定している例です。
myMovieClip.setFrameDuration(5, 2);
後からフレームの追加や削除もできます。addFrameAt()、removeFrameAt() メソッドを使います。全部で 5 フレームのアニメーションの 10 フレーム目に追加する、といったような指定はできません。
myMovieClip.addFrameAt(5, frames[10]) myMovieClip.removeFrameAt(5)
フレームのテクスチャを入れ替えることもできます。使うメソッドは setFrameTexture() です。
myMovieClip.setFrameTexture(5, frames[10]);
フレームに音を関連付けることもできます。setFrameSound() メソッドを使います。
[Embed(source="step.mp3")] private static const StepSound:Class; myMovieClip.setFrameSound(5, new StepSound() as Sound);
これで、5 フレーム目が表示されるタイミングで、指定した音が再生されます。
フレームに直接スクリプトを関連付けることはできません。代わりに Juggler.delayCall() メソッドが使用できます。
以上で、Starling のアニメーションの基本は終わりです。見ての通り、Starling は表現の柔軟さでは CPU 描画にかないません。高速な描画を安定して行いたい場合の選択肢という位置づけあたりが適当そうです。
こういう記事が欲しかった!
後から勉強します!