【連載】Starlingフレームワークを用いたStage3Dによる2Dアニメーション 第3回 StarlingフレームワークのTweenクラスによるアニメーション [Edit]

Starlingフレームワークには、スクリプトでトゥイーンアニメーションを行うstarling.animation.Tweenクラスが備わっています。ActionScript 3.0に定義済みのfl.transitions.Tweenクラスとは少し使い勝手が違います。StarlingフレームワークのTweenクラスを用いたアニメーションについてご説明します。

  • サンプルファイル: スクリプト003 (Starling_03_003.zip/Flash CS6形式/約25KB)
    ダウンロードファイルには、Starlingフレームワークのライブラリは含まれていません。予めインストールしてください。

01 [ライブラリ]のビットマップをステージに置く

まず、トゥイーンアニメーションさせるインスタンスを、ステージに置かなければなりません。今回は、[ライブラリ]のビットマップからTextureオブジェクトをつくり、それをImageインスタンスに入れてStarlingルートクラスの子に加えます。そのため、[ライブラリ]のビットマップには、予めクラス(Pen)を定めておきます(図001)。

図001■[ライブラリ]のビットマップにクラスを設定
図001上
図001下

Flashムービー(FLA)ファイルには、メインタイムラインにつぎの3行のフレームアクションを書きます。そして、Starlingルートクラス(MySprite)を以下のように定めれば、[ライブラリ]のビットマップイメージを納めたImageインスタンスがステージの左端に描かれます(図002)。これらのスクリプトについて詳しくは、本連載第1回「Starlingフレームワークで書く初めてのアニメーション」をお読みください。

// フレームアクション: メインタイムライン
import starling.core.Starling;
var myStarling:Starling = new Starling(MySprite, stage);
myStarling.start();
// ActionScript 3.0クラスファイル: MySprite.as
package  {
	import starling.display.Sprite;
	import starling.display.Image;
	import starling.textures.Texture;
	import starling.events.Event;
	import flash.display.BitmapData;
	public class MySprite extends Sprite {
		private var instance:Image;
		public function MySprite() {
			addEventListener(Event.ADDED_TO_STAGE, initialize);
		}
		private function initialize(eventObject:Event):void {
			var myBitmapData:BitmapData = new Pen();
			var myTexture:Texture = Texture.fromBitmapData(myBitmapData);
			instance = new Image(myTexture);
			instance.pivotX = instance.width / 2;
			instance.pivotY = instance.height / 2;
			instance.y = stage.stageHeight / 2;
			addChild(instance);
		}
	}	
}

図002■[ライブラリ]のビットマップイメージを納めたインスタンスがステージ左端に描かれた
図002

02 Tweenクラスで簡単なトゥイーンアニメーションを定める

StarlingフレームワークのTweenクラスで、ごく簡単なアニメーションを定めましょう。手順は大きく、つぎの3つになります。

  1. Tweenインスタンスをつくる。
  2. トゥイーンを定める。
  3. Jugglerに加える。

トゥイーンのアニメーションを設定するには、まずTweenクラスのコンストラクタメソッドでTweenインスタンスをつくります。引数は3つで、アニメーションさせるインスタンスとその時間、およびイージングの指定です。イージングはTransitionsクラスの定数から選びます(デフォルト値はイージングのない等速のTransitions.LINEAR)。

new Tween(インスタンス, 時間, イージング);

つぎに、アニメーションさせるプロパティに応じたメソッドを呼出します。ここでは、インスタンスの位置を右端に動かします。xy座標を移動させるメソッドはTween.moveTo()で、引数ふたつが移動する先のxy座標です。

Tweenオブジェクト.moveTo(x座標, y座標)

そして、アニメーションを始めます。これがTweenクラスのメソッドではありません。StarlingオブジェクトがもつJugglerオブジェクトを用いるのです。静的プロパティStarling.jugglerで参照したJugglerオブジェクトに、Juggler.add()メソッドでTweenインスタンスを加えます。Jugglerオブジェクトは、本連載第2回「Starlingフレームワークでスプライトシートを使う」04「スプライトシートに書出したフレームアニメーションをインスタンスで再生する」でご紹介しました。

Starling.juggler.add(Tweenオブジェクト)

以上の3つの手順を済ませると、インスタンスにイージングのかかった動きが加えられます。前掲Starlingルートクラス(MySprite)を書替えた後に掲げるスクリプト001は、ステージ左端に置いたインスタンスを右端までトゥイーンアニメーションさせます(図003)。イージングは、トゥイーンの初めと終わりに弾力のある変化を与えるTransitions.EASE_IN_OUT_ELASTICにしました。

図003■ステージ左端のインスタンスが右端にトゥイーンアニメーションする
図003

import宣言には、TweenインスタンスをつくるのにTweenとTransitionsクラス、Jugglerオブジェクトを使うためにStarlingクラスが加わります。

import starling.core.Starling;
// ...[中略]...
import starling.animation.Tween;
import starling.animation.Transitions;

そして、前述の3つのトゥイーンを定める手順は、新たなメソッド(setTween())で行いました。これは、初期化のメソッド(initialize())から呼出しています。

private function initialize(eventObject:Event):void {
    // ...[中略]...
    setTween();
}
private function setTween():void {
    var myTween:Tween = new Tween(instance, 7, Transitions.EASE_IN_OUT_ELASTIC);
    myTween.moveTo(stage.stageWidth - instance.width / 2, instance.y);
    Starling.juggler.add(myTween);
}

スクリプト001■Tweenクラスでインスタンスを水平にアニメーションさせる

// ActionScript 3.0クラスファイル: MySprite.as
package  {
	import starling.core.Starling;
	import starling.display.Sprite;
	import starling.display.Image;
	import starling.textures.Texture;
	import starling.events.Event;
	import starling.animation.Tween;
	import starling.animation.Transitions;
	import flash.display.BitmapData;
	public class MySprite extends Sprite {
		private var instance:Image;
		public function MySprite() {
			addEventListener(Event.ADDED_TO_STAGE, initialize);
		}
		private function initialize(eventObject:Event):void {
			var myBitmapData:BitmapData = new Pen();
			var myTexture:Texture = Texture.fromBitmapData(myBitmapData);
			instance = new Image(myTexture);
			instance.pivotX = instance.width / 2;
			instance.pivotY = instance.height / 2;
			instance.y = stage.stageHeight / 2;
			addChild(instance);
			setTween();
		}
		private function setTween():void {
			var myTween:Tween = new Tween(instance, 7, Transitions.EASE_IN_OUT_ELASTIC);
			myTween.moveTo(stage.stageWidth - instance.width / 2, instance.y);
			Starling.juggler.add(myTween);
		}
	}	
}

03 複数のプロパティをトゥイーンする

前掲スクリプト001では、座標のプロパティをトゥイーンしました。けれど、ひとつのTweenインスタンスに異なるプロパティを定めて、同時にトゥイーンすることもできます。アルファはTween.fadeTo()、伸縮率にはTween.scaleTo()というメソッドが備わっています。その他のプロパティも、Tween.animate()メソッドの引数に指定してトゥイーンアニメーションできます(表001)。

表001■Tweenクラスのトゥイーンを定めるメソッド
トゥイーンを定めるメソッド 引数 トゥイーンされるプロパティ
animate(property:String, targetValue:Number):void property − トゥイーンするプロパティを定める文字列。
targetValue − トゥイーンが達するプロパティ値。
第1引数で定めたプロパティ。
fadeTo(alpha:Number):void alpha − トゥイーンが達するアルファ値(0〜1.0)。 alpha
moveTo(x:Number, y:Number):void x − トゥイーンが達するx座標値。
y − トゥイーンが達するy座標値。
xとy
scaleTo(factor:Number):void factor − トゥイーンが達する垂直と水平伸縮率。
scaleXとscaleY

前掲スクリプト001でトゥイーンするプロパティを増やします。インスタンスのアルファと伸縮率は0.5にして、角度を一周回しましょう。手直しするのは、トゥイーンを定めるメソッド(setTween())です。新たにトゥイーンに加えたいプロパティを、それぞれのメソッドでTweenインスタンスに設定します。

private function setTween():void {
	var myTween:Tween = new Tween(instance, 7, Transitions.EASE_IN_OUT_ELASTIC);
	myTween.moveTo(stage.stageWidth - instance.width / 2, instance.y);
	myTween.fadeTo(0.5);
	myTween.scaleTo(0.5);
	myTween.animate("rotation", Math.PI * 2);
	Starling.juggler.add(myTween);
}

書直したStarlingルートクラス(MySprite)が、つぎのスクリプト002です。トゥイーンしたインスタンスは、左端から右端に動くとともに、アルファと大きさが半分になりながら1回転します(図004)。

スクリプト002■インスタンスの位置に加えてアルファと伸縮率および回転角をトゥイーンする

// ActionScript 3.0クラスファイル: MySprite.as
package  {
	import starling.core.Starling;
	import starling.display.Sprite;
	import starling.display.Image;
	import starling.textures.Texture;
	import starling.events.Event;
	import starling.animation.Tween;
	import starling.animation.Transitions;
	import flash.display.BitmapData;
	public class MySprite extends Sprite {
		private var instance:Image;
		public function MySprite() {
			addEventListener(Event.ADDED_TO_STAGE, initialize);
		}
		private function initialize(eventObject:Event):void {
			var myBitmapData:BitmapData = new Pen();
			var myTexture:Texture = Texture.fromBitmapData(myBitmapData);
			instance = new Image(myTexture);
			instance.pivotX = instance.width / 2;
			instance.pivotY = instance.height / 2;
			instance.y = stage.stageHeight / 2;
			addChild(instance);
			setTween();
		}
		private function setTween():void {
			var myTween:Tween = new Tween(instance, 7, Transitions.EASE_IN_OUT_ELASTIC);
			myTween.moveTo(stage.stageWidth - instance.width / 2, instance.y);
			myTween.fadeTo(0.5);
			myTween.scaleTo(0.5);
			myTween.animate("rotation", Math.PI * 2);
			Starling.juggler.add(myTween);
		}
	}	
}
図004■インスタンスが左端から右端に動くとともにアルファと大きさは半分になりながら1回転する
図004

04 複数のTweenインスタンスを用いて順にアニメーションさせる

異なるトゥイーンが定められたTweenインスタンスを複数つくって、順にアニメーションさせることもできます。そこで、トゥイーンのイージングをいくつか変えてみることにします。

Transitionsクラスには、イージングのないデフォルトの等速(定数Transitions.LINEAR)以外に16のイージングが備わっています。これは下表002のように、値の変わり方が標準・反動・バウンド・弾力の4種類あり、それぞれについてトゥイーンの始まりと終わりにどう変化を加えるか4つずつのバリエーションがあるからです。

変化の加え方は、標準についてご説明すれば、始まりに加速(in)、終わりに減速(out)、始まりに加速しつつ終わりに減速(in-out)、真ん中に向かって減速してそれから加速(out-in)の4つになります。リファレンスのTransitionsクラスのページ初めに16のイージングがグラフで掲げられていますので、併せてご参照ください。

表002■Transitionsクラスのイージングを定める定数
変化 定数
in out in-out out-in
標準 EASE_IN EASE_OUT EASE_IN_OUT EASE_OUT_IN
反動 EASE_IN_BACK EASE_OUT_BACK EASE_IN_OUT_BACK EASE_OUT_IN_BACK
バウンド EASE_IN_BOUNCE EASE_OUT_BOUNCE EASE_IN_OUT_BOUNCE EASE_OUT_IN_BOUNCE
弾力 EASE_IN_ELASTIC EASE_OUT_ELASTIC EASE_IN_OUT_ELASTIC EASE_OUT_IN_ELASTIC

前掲スクリプト002にさらに手を加えて、3つの異なるイージングのトゥイーンで順にアニメーションさせてみましょう。イージングはTransitions.EASE_IN_OUT_ELASTICTransitions.EASE_IN_OUT_BOUNCEおよびTransitions.EASE_OUT_IN_ELASTICを選びました。それぞれのイージングごとに、Tweenインスタンスもつくらなければなりません。そこで、3つのTransitionsクラスの定数は、予め(Stringベース型)Vectorオブジェクト(myTransitions)に入れておきます。

private var myTransitions:Vector.<String>;
private function initialize(eventObject:Event):void {
    // ...[中略]...
    myTransitions = new <String>[
        Transitions.EASE_IN_OUT_ELASTIC,
        Transitions.EASE_IN_OUT_BOUNCE,
        Transitions.EASE_OUT_IN_ELASTIC
    ];
    // ...[中略]...
}

つぎのトゥイーンに切換えるには、前のトゥイーンが終わったことを知らなければなりません。ActionScript 3.0のお約束なら、イベントリスナーで扱うところです。けれども、StarlingフレームワークのTweenクラスではコールバック関数(イベントハンドラ)を使います。TweenクラスにはTween.onCompleteプロパティがあり、予めコールバック関数を定めておくと、トゥイーンが終わったときに呼出されるのです。

イベントハンドラは、トゥイーンを定めるメソッド(setTween())の中で設定します。メソッドは、イージングの定数を納めたVectorオブジェクトにエレメントがあるか確かめたうえで、エレメントの定数を取出します。そして、その定数のイージングでTweenインスタンスをつくったら、トゥイーンの設定を行います。そのとき、Tween.onCompleteプロパティにコールバック関数も定めるのです。その関数は、このメソッド自身になります。

private function setTween():void {
    if (myTransitions.length) {
        var myTransition:String = myTransitions.shift();
        var myTween:Tween = new Tween(instance, 7, myTransition);
        // トゥイーンの設定
        myTween.onComplete = setTween;
        Starling.juggler.add(myTween);
        // ...[中略]...
    }
}

あとは、トゥーンするプロパティをどう決めるかです。アニメーションするインスタンスの位置は右端と左端を、行ったり来たりすることにします。そこで、他のプロパティも右端と左端の値を交互に繰返します。

この場合、各プロパティ値を予めどのようにもっておくかです。考えやすいのは、イージングの定数と同じエレメント数(3)のVectorオブジェクトに、トゥイーンごとの値をエレメントとして納めておくことでしょう。

けれど、ここでは以下のように交互に繰返すふたつの値だけを、Vectorオブジェクト(positionsとratiosおよびradians)のエレメントにしました。そして、使うのがどちらのエレメントかは、インデックスの変数(i)を宣言して定めます。Vectorオブジェクトのエレメントはふたつだけですので、インデックス変数の値は0と1を交互に切換えることになります。

整数0と1を互いに反転するには、ビット単位の排他的論理和演算子^が使えます[*1]。ビット単位の論理演算は、整数を2進数の桁ごとに計算し、繰り上がりや繰り下がりはありません。変数(i)には整数の1か0を使うとしたとき、1との排他的論理和(i ^= 1)をとると、1は0に0は1に反転します。

private var positions:Vector.<Number>;
private var ratios:Vector.<Number> = new <Number>[0.5, 1];
private var radians:Vector.<Number> = new <Number>[Math.PI * 2, -Math.PI * 2];
private var i:uint = 0;
// ...[中略]...
private function initialize(eventObject:Event):void {
    // ...[中略]...
    positions = new <Number>[stage.stageWidth - halfWidth / 2, halfWidth];
    // ...[中略]...
}
// ...[中略]...
private function setTween():void {
    if (myTransitions.length) {
        var myTransition:String = myTransitions.shift();
        var ratio:Number = ratios[i];
        var myTween:Tween = new Tween(instance, 7, myTransition);
        myTween.moveTo(positions[i], instance.y);
        myTween.fadeTo(ratio);
        myTween.scaleTo(ratio);
        myTween.animate("rotation", radians[i]);
        // ...[中略]...
        i ^= 1;
    }
}

前掲スクリプト002にこれらの修正を加えたのが、つぎのスクリプト003です。3つの異なるイージングを定めたトゥイーンが、順にアニメーションとして実行されます。

スクリプト003■3つのTweenオブジェクトのトゥイーンを順にアニメーションさせる

// ActionScript 3.0クラスファイル: MySprite.as
package  {
	import starling.core.Starling;
	import starling.display.Sprite;
	import starling.display.Image;
	import starling.textures.Texture;
	import starling.events.Event;
	import starling.animation.Tween;
	import starling.animation.Transitions;
	import flash.display.BitmapData;
	public class MySprite extends Sprite {
		private var instance:Image;
		private var myTransitions:Vector.<String>;
		private var positions:Vector.<Number>;
		private var ratios:Vector.<Number> = new <Number>[0.5, 1];
		private var radians:Vector.<Number> = new <Number>[Math.PI * 2, -Math.PI * 2];
		private var i:uint = 0;
		public function MySprite() {
			addEventListener(Event.ADDED_TO_STAGE, initialize);
		}
		private function initialize(eventObject:Event):void {
			var myBitmapData:BitmapData = new Pen();
			var myTexture:Texture = Texture.fromBitmapData(myBitmapData);
			instance = new Image(myTexture);
			var halfWidth:Number = instance.width / 2;
			myTransitions = new <String>[
				Transitions.EASE_IN_OUT_ELASTIC,
				Transitions.EASE_IN_OUT_BOUNCE,
				Transitions.EASE_OUT_IN_ELASTIC
			];
			positions = new <Number>[stage.stageWidth - halfWidth / 2, halfWidth];
			instance.pivotX = halfWidth;
			instance.pivotY = instance.height / 2;
			instance.y = stage.stageHeight / 2;
			addChild(instance);
			setTween();
		}
		private function setTween():void {
			if (myTransitions.length) {
				var myTransition:String = myTransitions.shift();
				var ratio:Number = ratios[i];
				var myTween:Tween = new Tween(instance, 7, myTransition);
				myTween.moveTo(positions[i], instance.y);
				myTween.fadeTo(ratio);
				myTween.scaleTo(ratio);
				myTween.animate("rotation", radians[i]);
				myTween.onComplete = setTween;
				Starling.juggler.add(myTween);
				i ^= 1;
			}
		}
	}	
}

中級の読者の中にはひとつ疑問をもたれた方もあるかもしれません。前掲スクリプト003のトゥイーンを定めるメソッド(setTween())は、新たなTweenインスタンスをつくってはStarlingオブジェクトのもつJugglerオブジェクトにJuggler.add()メソッドで加えています。トゥイーンアニメーションが正しく行われるのは、Tweenインスタンスの参照がJugglerオブジェクトによって保たれているからです。では、トゥイーンが済んだら、そのTweenインスタンスをJugglerオブジェクトから除かないと、参照がメモリに残ったままにならないでしょうか。

池上彰さんではありませんが、それは「いい質問です」。Tweenインスタンスのトゥイーンアニメーションが終わると、Jugglerオブジェクトはいわれなくてもインスタンスを除いてくれます[*2]。Tweenインスタンスがほかに参照されていなければ、やがて(ガベージコレクションにより)メモリから消え去ります。もちろん、Tweenインスタンスがアニメーションさせたオブジェクト(DisplayObject)は、そのかぎりではありません。表示リストから外したり、さらにリスナーその他の参照を消すことはスクリプトの書き手の責任です。

[*1] ビット単位の論理演算は2進数で考えますので、結果は0と1の4とおりの組合わせで示せます。ビット単位の排他的論理和演算子^の演算結果は表003のとおりです。ビット単位の論理演算について詳しくは、F-siteセミナー「ActionScriptでの最速を求める」02-04「ビット演算をどう使うか」をお読みください。

表003■ビット単位の排他的論理和演算子^の演算結果
ビット単位の論理和演算 結果の2進数
0 ^ 0 0
0 ^ 1
1 ^ 0
1
1 ^ 1 0

[*2] Starling Wiki「The Starling Manual」の「Animation」で解説された「The Juggler」には、つぎのように述べられています(筆者訳)。

TweenはJugglerからいちいち消さなくて構いません。トゥイーンが済んでしまえば、それらは自動的に除かれます。
(Tweens don't have to be removed from the juggler manually; they will be removed automatically once they are finished. )

 

その他の記事