Starlingフレームワークにはstarling.animation.Tweenクラスが備わっています。ただし、Flashにもともとあるfl.transitions.Tweenクラスとは少し使い勝手が違います。StarlingフレームワークのTweenクラスを用いたアニメーションについてご説明します。
01 Tweenクラスを使ったアニメーション
水平のアニメーションを試すため、Quadインスタンスをステージ左端に置きます(図001)。Starlingフレームワークのルートオブジェクトをつくるクラス(MySprite)は、つぎのように定めます(このクラスの内容については「Starlingフレームワークを使う」をお読みください)。
  
    | 
// ActionScript 3.0クラス定義ファイル: MySprite.aspackage {
 import starling.core.Starling;
 import starling.display.Sprite;
 import starling.display.Quad;
 import starling.events.Event;
 public class MySprite extends Sprite {
 private var myQuad:Quad;
 public function MySprite() {
 addEventListener(Event.ADDED_TO_STAGE, initialize);
 }
 private function initialize(eventObject:Event):void {
 myQuad = new Quad(50, 10, 0x0000FF);
 myQuad.pivotX = myQuad.width / 2;
 myQuad.pivotY = myQuad.height / 2;
 myQuad.y = stage.stageHeight / 2;
 addChild(myQuad);
 }
 }
 }
 | 
図001■ステージの左端にQuadインスタンスを置く

なお、このクラス(MySprite)と同じ場所に保存したFlashムービー(FLA)ファイルには、つぎのようなフレームアクションを書いておくものとします(パブリッシュ設定など、Starlingフレームワークを使うために必要な準備についても前出「Starlingフレームワークを使う」参照)。
  
    | 
// フレームアクション: メインタイムラインimport starling.core.Starling;
 var myStarling:Starling = new Starling(MySprite, stage);
 myStarling.start();
 | 
このQuadインスタンスにトゥイーンのアニメーションを設定するには、まずTweenクラスのコンストラクタメソッドでTweenインスタンスをつくります。引数は3つで、アニメーションさせるインスタンスとその時間、およびイージングの指定です。イージングはTransitionsクラスの定数から選びます(デフォルト値はイージングのない等速のTransitions.LINEAR)[*1]。
new Tween(インスタンス, 時間, イージング);
つぎに、アニメーションさせるのが何かをメソッドの呼出しで決めます。xy座標の平行移動は、Tween.moveTo()メソッドで、ふたつの引数はもちろんxy座標です。移動する先の座標値を渡します。
Tweenオブジェクト.moveTo(x座標, y座標)
そして、アニメーションを始めます。これがTweenクラスのメソッドではありません。StarlingオブジェクトがもつJugglerというオブジェクトに、Juggler.add()メソッドでTweenインスタンスを加えるのです。なお、Jugglerオブジェクトは静的プロパティStarling.jugglerで参照します[*2]。
Starling.juggler.add(Tweenオブジェクト)
以上の3つの処理を加えると、インスタンスにイージングのかかった動きが適用されます。つぎのスクリプト001は、Quadインスタンスをステージ左端から右端までアニメーションさせます。イージングはTransitions.EASE_IN_OUT_ELASTICにしました。
スクリプト001■黒TweenクラスでQuadインスタンスをステージの左端から右端までアニメーションさせる
  
    | 
// ActionScript 3.0クラス定義ファイル: MySprite.as
package {  import starling.core.Starling;  import starling.display.Sprite;  import starling.display.Quad;  import starling.events.Event;  import starling.animation.Tween;  import starling.animation.Transitions;  public class MySprite extends Sprite {    private var myQuad:Quad;    private var duration:Number = 4;    public function MySprite() {      addEventListener(Event.ADDED_TO_STAGE, initialize);    }    private function initialize(eventObject:Event):void {      myQuad = new Quad(50, 10, 0x0000FF);      myQuad.pivotX = myQuad.width / 2;      myQuad.pivotY = myQuad.height / 2;      myQuad.y = stage.stageHeight / 2;      var myTween:Tween = new Tween(myQuad, duration, Transitions.EASE_IN_OUT_ELASTIC);      myTween.moveTo(stage.stageWidth, myQuad.y);      Starling.juggler.add(myTween);      addChild(myQuad);    }  }} | 
  
    | [*1] それぞれのイージングの値が時間軸に対してどう変化するかは、リファレンスのTransitionsクラス冒頭にグラフで掲げられています。 [*2] 厳密には、Starling.jugglerが静的プロパティなのではなく、現行のStarlingオブジェクトがStarlingという静的プロパティ(getアクセサメソッド)に納められています。したがって、現行StarlingオブジェクトのStarling.jugglerプロパティを参照することになります。 | 
02 アニメーションの終わりを捉える
いくつかのイージングを順に試してみましょう。試したいイージングのTransitionsクラス定数を、予めVectorインスタンスに入れておきます。そして、アニメーションがひとつ終わるたびに、このVectorオブジェクトから順に取出した定数で新たなイージングのアニメーションを実行します。
  
    | 
var myTransitions:Vector.<String> = new <String>[Transitions.EASE_IN_OUT_ELASTIC,
 Transitions.EASE_IN_OUT_BOUNCE,
 Transitions.EASE_OUT_IN_ELASTIC
 ];
 | 
そうするためには、アニメーションの終わりを捉えなければなりません。ActionScript 3.0のお約束なら、イベントリスナーを使うところです(fl.transitions.TweenクラスではTween.motionFinishイベント)。けれど、StarlingフレームワークのTweenクラスでは、Tween.onCompleteプロパティにイベントハンドラ(コールバック)のメソッド(関数)を設定します。
つぎのスクリプト002は、新たに定めた関数(nextTween())でアニメーションの設定を行います(第31〜41行目)。イージングと移動先をVectorオブジェクトから順に取出して切替え、Tween.onCompleteプロパティに自身のメソッドを設定しています(第39行目)。
スクリプト002■Tween.onCompleteプロパティに設定したメソッドでイージングを切替える
  
    | 
// ActionScript 3.0クラス定義ファイル: MySprite.as
package {  import starling.core.Starling;  import starling.display.Sprite;  import starling.display.Quad;  import starling.events.Event;  import starling.animation.Tween;  import starling.animation.Transitions;  public class MySprite extends Sprite {    private var myQuad:Quad;    private var myTransitions:Vector.<String>;    private var positionsX:Vector.<Number>;    private var duration:Number = 4;    public function MySprite() {      addEventListener(Event.ADDED_TO_STAGE, initialize);    }    private function initialize(eventObject:Event):void {      var nRight:Number = stage.stageWidth;      myTransitions = new <String>[        Transitions.EASE_IN_OUT_ELASTIC,        Transitions.EASE_IN_OUT_BOUNCE,        Transitions.EASE_OUT_IN_ELASTIC        ];      positionsX = new <Number>[nRight, 0, nRight];      myQuad = new Quad(50, 10, 0x0000FF);      myQuad.pivotX = myQuad.width / 2;      myQuad.pivotY = myQuad.height / 2;      myQuad.y = stage.stageHeight / 2;      addChild(myQuad);      nextTween();    }    private function nextTween():void {      var nLength:uint = myTransitions.length;      if (nLength > 0) {        var myTransition:String = myTransitions.shift();        var positionX:Number = positionsX.shift();        var myTween:Tween = new Tween(myQuad, duration, myTransition);        myTween.moveTo(positionX, myQuad.y);        Starling.juggler.add(myTween);        myTween.onComplete = nextTween;      }    }  }} | 
これで、Vectorオブジェクトに加えたイージングが順に設定されて、Quadインスタンスのアニメーションが実行されます。
03 【Advanced】Jugglerオブジェクトの仕事
少し踏み込んだ話題として、Jugglerオブジェクトがどのようにアニメーションを進めているのか、Starlingフレームワークのクラス(ASファイル)を抜粋してご説明します(クラス定義の行番号をご参考までに添えました。ただし、バージョンの違いによって行は変わります)。
Jugglerオブジェクトは、Juggler.add()メソッド(第56〜59行目)で加えられたインスタンスに対して、advanceTime()メソッドを呼出します(第119行目)。TweenクラスにはTween.advanceTime()メソッドが備わっていて、引数の経過時間に応じてインスタンスの表示を変えます。このメソッドが繰返し引数値を変えて呼出されることによって、インスタンスのアニメーションが行われるのです。
  
    | 
public class Juggler implements IAnimatable{  private var mObjects:Vector.<IAnimatable>; 
  public function Juggler()  { 
    mObjects = new <IAnimatable>[];  } 
  public function add(object:IAnimatable):void  {    if (object != null) mObjects.push(object);  } 
  public function advanceTime(time:Number):void  { 
    var i:int;    var numObjects:int = mObjects.length;    var objectCopy:Vector.<IAnimatable> = mObjects.concat(); 
    for (i=0; i < numObjects; ++i)      objectCopy[i].advanceTime(time); 
  }} | 
advanceTime()メソッドは、インターフェイスIAnimatableが定めています。JugglerとTweenクラスは、ともにこのインターフェイスを実装しています。そして、Juggler.advanceTime()メソッド(前掲第106〜131行目)は、Starlingオブジェクトから呼出されます。
Starlingクラスは内部的に(privateの)render()メソッド(第233〜254行目)から、自身がもつJugglerオブジェクトに対してJuggler.advanceTime()メソッドを呼出しています(第242行目)。render()メソッドは、イベントEvent.ENTER_FRAMEに定められたリスナーメソッド(第319〜323行目)から呼出されます。したがって、Juggler.advanceTime()メソッドは、フレームごとに実行されることになるのです。
  
    | 
public class Starling{ 
  private var mJuggler:Juggler; 
  public function Starling(rootClass:Class, stage:flash.display.Stage,                viewPort:Rectangle=null, stage3D:Stage3D=null,               renderMode:String="auto")   { 
    mJuggler = new Juggler(); 
    stage.addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true); 
  } 
  private function render():void  { 
    mJuggler.advanceTime(passedTime); 
  } 
  private function onEnterFrame(event:Event):void  { 
    if (mStarted) render();  } 
}
 | 
この仕組みの中でイベントリスナーは使わず、インターフェイスで定められたイベントハンドラ(コールバック)メソッドを呼出すことにしたのは、処理の速さを稼ぐためだと推測されます。Event.ENTER_FRAMEのような繰返し発生するイベントはひとつのオブジェクトが代表して受取り、他の数多くのオブジェクトに対してはコールバック関数を呼出すという仕組みは、最適化の手法のひとつとされています[*3]。
  
    | [*3] イベントリスナーとコールバックの比較については、Adobe Flash Platform「Flash Platform のパフォーマンスの最適化」の「イベントモデルとコールバック」が参考になるでしょう。 | 
作成者: 野中文雄
更新日: 2013年1月2日 Tweenクラスのコンストラクタメソッドのリンク、注[*1]の説明の一部、およびスクリプト002の変数名を修正。
  作成日: 2012年2月14日