【連載】Starlingフレームワークを用いたStage3Dによる2Dアニメーション 第6回 Starlingフレームワーク1.3の新たなフィルタのクラスとトゥイーンのメソッド [Edit]

2013年1月14日にStarlingフレームワーク1.3が公開されました。その中でも、表現の幅を拡げる新たなフィルタの機能について解説します。また、トゥイーンにも使いやすいメソッドがひとつ加わりましたので、簡単にご紹介しましょう。

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

01 新たなフィルタのクラス

新たにstarling.filtersパッケージが加わり、ぼかし(BlurFilter)とカラーマトリクス(ColorMatrixFilter)のフィルタが備わりました(図001)。なお、FragmentFilterは基本クラスとしてフィルタの各クラスに継承され、FragmentFilterModeクラスはフィルタのモードを定めます。

    継承
  • BlurFilter → FragmentFilter → Object
  • ColorMatrixFilter → FragmentFilter → Object

図001■starling.filtersパッケージのクラス
図001

フィルタはDisplayObjectインスタンスのDisplayObject.filterプロパティにオブジェクトを与えて適用します。プロパティ名をよくご覧ください。定義済みActionScript 3.0(DisplayObject.filtersプロパティ)と違って単数形です。つまり、フィルタのオブジェクトを配列に入れたりはせず、直に定めることにご注意ください。

DisplayObjectオブジェクト.filter = フィルタオブジェクト

フィルタは直接GPUで処理されるので、きわめて高速です(「Starling 1.3」参照)。

02 BlurFilterクラスでぼかし・ドロップシャドウ・光彩フィルタをかける

BlurFilterクラスは、オブジェクトにガウスぼかしを与えます。ぼかす強さは、水平方向と垂直方向に分けて定められます。ただし、水平・垂直の直交軸はインスタンスごとではなく、つねにステージに対して決まります。

BlurFilterクラスの役目は、オブジェクトのかたちでぼかしをつくることです。そのぼかしをオブジェクトと別につくれば、ドロップシャドウや光彩(グロー)としても使えます。そこで、それぞれの機能が、静的メソッドBlurFilter.createDropShadow()およびBlurFilter.createGlow()として備わりました。ともにBlurFilterインスタンスを返しますので、DisplayObjectインスタンスに適用します。

まず、基本となるぼかしフィルタの構文からご紹介します。BlurFilter()コンストラクタでインスタンスをつくります。引数ははじめのふたつが、それぞれ水平方向と垂直方向のぼかしの強さです。そして、3つ目がぼかすきめの細かさを定めます。値は小さいほど粗くなるものの、負荷は下がります。引数は3つとも省くことができ、デフォルト値はすべて1です。

new BlurFilter(水平のぼかし, 垂直のぼかし, きめ細かさ)

つぎのスクリプトは、デフォルト値でぼかしフィルタのBlurFilterオブジェクト(myFilter)をつくり、DisplayObjectインスタンス(instance)に適用します(図002)。

var myFilter:BlurFilter = new BlurFilter();
instance.filter = myFilter;
図002■BlurFilterインスタンスでオブジェクトにデフォルト値のぼかしフィルタをかける
図002左
もとのイメージ

 
図002右
ぼかし

つぎに、ドロップシャドウフィルタです。静的メソッドBlurFilter.createDropShadow()には、4つの引数が定められます(すべて省いても構いません)。引数は順に、影の長さ(4)、ラジアン角(π/4 = 45度)、カラー(0x0)、アルファ(0.5)、ぼかし(1)、きめ細かさ(0.5)となります(括弧内の数値はデフォルト値)。

BlurFilter.createDropShadow(長さ, ラジアン角, カラー, アルファ, ぼかし, きめ細かさ)

つぎのスクリプトはBlurFilter.createDropShadow()メソッドにより、影の長さ8、角度は30度(π/6ラジアン)、カラー0x000066(暗い青)、アルファ0.8のドロップシャドウが定められたBlurFilterオブジェクト(myFilter)を得て、 DisplayObjectインスタンス(instance)に与えます(図003)。

var myFilter:BlurFilter = BlurFilter.createDropShadow(8, Math.PI / 6, 0x000066, 0.8);
instance.filter = myFilter;

図003■BlurFilter.createDropShadow()メソッドでオブジェクトにドロップシャドウをかけた
図003

そして、静的メソッドBlurFilter.createGlow()がインスタンスに光彩(グロー)を加えます。引数の定めはBlurFilter.createDropShadow()メソッドの第3引数以降と同じで、カラー(0xFFFF00)、アルファ(1)、ぼかし(1)、きめ細かさ(0.5)です(括弧内のデフォルト値はBlurFilter.createDropShadow()メソッドと少し違います)。

BlurFilter.createGlow(カラー, アルファ, ぼかし, きめ細かさ)

つぎのスクリプトは、BlurFilter.createGlow()メソッドにより、シアン(0x00FFFF)でアルファ0.8、ぼかし4の光彩をBlurFilterオブジェクト(myFilter)として定め、DisplayObjectインスタンス(instance)に与えます(図004)。

var myFilter:BlurFilter = BlurFilter.createGlow(0x00FFFF, 0.8, 4);
instance.filter = myFilter;
図004■BlurFilter.createGlow()メソッドでオブジェクトに光彩を与えた
図004

03 ColorMatrixFilterクラスでカラーを調整する

ColorMatrixFilterクラスを使うと、インスタンスの明度・コントラスト・色相・彩度などのカラーが調整できます。[プロパティ]インスペクタの[フィルター]で[カラー調整]を選んで加えられる操作と同じです(図005)。

図005■[プロパティ]インスペクタの[フィルター]で[カラー調整]を選択
図005

ColorMatrixFilterインスタンスに対して以下の表001のようなメソッドを呼出すことにより、明度・コントラスト・色相・彩度が定められます。これらのメソッドには、いずれも0を中心とした±1の範囲が基本となる引数値を渡します。また、ひとつのColorMatrixFilterインスタンスにこれらのメソッドを複数呼出せば、カラー調整が組合わせられます。

表001■ColorMatrixFilterクラスのカラーを調整するメソッド
ColorMatrixFilter
クラスのメソッド
基本の引数値 カラー調整
adjustBrightness() -1〜1 明度
adjustContrast() -1〜1 コントラスト
adjustHue() -1〜1 色相
adjustSaturation() -1〜1 彩度

つぎのスクリプトは、ColorMatrixFilterインスタンス(myFilter)をつくり、ColorMatrixFilter.adjustSaturation()メソッドで引数-1の無彩色(グレースケール)を定めて、オブジェクト(instance)に適用します(図006)。

var myFilter:ColorMatrixFilter = new ColorMatrixFilter();
myFilter.adjustSaturation(-1);
instance.filter = myFilter;
図006■ColorMatrixFilter.adjustSaturation()メソッドでオブジェクトのカラーをグレースケールにする
図006左
もとのイメージ

 
図006右
彩度: -1

複数のカラー調整を組合わせてみましょう。つぎのスクリプトは、ColorMatrixFilterインスタンス(myFilter)に、ColorMatrixFilter.adjustHue()ColorMatrixFilter.adjustBrightness()、およびColorMatrixFilter.adjustContrast()でそれぞれ色相・明度・コントラストを変えて、オブジェクト(instance)に適用します。オブジェクトの色相は赤めで、やや明るく、コントラストは強めました(図007)。

var myFilter:ColorMatrixFilter = new ColorMatrixFilter();
myFilter.adjustHue(3/4);
myFilter.adjustBrightness(0.2);
myFilter.adjustContrast(0.5);
instance.filter = myFilter;
図007■ColorMatrixFilterのメソッドで色相・明度・コントラストを変えてオブジェクトに適用した
図007

ColorMatrixFilterクラスは、4行×5列のRGBAカラー変換行列(カラーマトリクス)を表します。ColorMatrixFilter()コンストラクタには、引数としてカラー変換行列を渡すことができます。具体的な引数は、行列の1行目から4行目までを1本につなげたNumberベース型のVectorオブジェクトで定めます。

new ColorMatrixFilter(カラー変換行列を定めるVectorオブジェクト)

それでは、カラー変換行列でオブジェクトのカラーをセピア調にしてみましょう。つぎのスクリプトは、セピア調のカラー変換行列をVectorオブジェクト(colorSepia)に定め(Vectorオブジェクトのつくり方は「エレメントをもったVectorインスタンスの生成」参照)、ColorMatrixFilter()コンストラクタに渡してつくったColorMatrixFilterインスタンス(myFilter)をオブジェクト(instance)に適用します(図008)。

var colorSepia:Vector.<Number> = new <Number>[
	0.393, 0.769, 0.189, 0, 0,
	0.349, 0.686, 0.168, 0, 0,
	0.272, 0.534, 0.131, 0, 0,
	0, 0, 0, 1, 0
];
var myFilter:ColorMatrixFilter = new ColorMatrixFilter(colorSepia);
instance.filter = myFilter;
図008■ColorMatrixFilter()コンストラクタにセピア調のカラー変換行列を定めてオブジェクトに適用した
図008

04 Jugglerクラスの新たなメソッドでトゥイーンを加える

本連載第3回「StarlingフレームワークのTweenクラスによるアニメーション」02「Tweenクラスで簡単なトゥイーンアニメーションを定める」でご説明したとおり、トゥイーンはつぎの3つの手順で定めました。

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

しかし、この3つをまとめて行えるメソッドがJugglerクラスに備わりました。それは、Juggler.tween()メソッドです。初めのふたつの引数はTween()コンストラクタと同じ、トゥイーンさせるインスタンスとアニメーションにかける時間(秒数)です。そして、このJuggler.tween()メソッドの目玉は、なんといっても第3引数です。Tween()コンストラクタの第3引数に渡していたトランジション(イージング)も含めて、トゥイーンの内容はみんなObjectインスタンスのプロパティに放り込んでしまえばよいのです。もちろん、Jugglerクラスのメソッドですから、何もいわなくてもTweenインスタンスはJugglerオブジェクトに加えてくれます。

Jugglerオブジェクト.tween(インスタンス, 時間, トゥイーンを定めるObject)

たとえば、前出第3回「StarlingフレームワークのTweenクラスによるアニメーション」のスクリプト003「3つのTweenオブジェクトのトゥイーンを順にアニメーションさせる」では、トゥイーンをつぎのように定めました。Tween()コンストラクタの呼出しから始まり、Tweenクラスのメソッドでトゥイーンさせるオブジェクトのプロパティにさまざまなトゥイーンを定め、最後にJuggler.add()メソッドでTweenインスタンスをStarling.jugglerプロパティのオブジェクトに加えています。

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);

これがJuggler.tween()なら、メソッドひとつ呼出すだけでよく、トゥイーンの定めはすべて第3引数のObjectインスタンスにプロパティとして放り込んでおしまいです。

Starling.juggler.tween(instance, 7, {
    transition:myTransition,
    x:positions[i],
    alpha:ratio,
    scaleX:ratio,
    scaleY:ratio,
    rotation:radians[i],
    onComplete:setTween
});

このメソッドが優れものなのは、第3引数のObjectインスタンスに加えたプロパティをよく見るとわかります。transitionはTweenインスタンスのプロパティです。それに対して、xalphascaleXscaleYなどはトゥイーンするオブジェクト(DisplayObject)のプロパティです。さらに、onCompleteはTweenインスタンスに定めるイベントハンドラ、と中身はまちまちです。これらをすべてJuggler.tween()メソッドが仕分けてくれています。

第3回スクリプト003をJuggler.tween()メソッドで書替えたStarlingルートクラス(MySprite)の定義全体は、つぎのスクリプト001のとおりです。

スクリプト001■Juggler.tween()メソッドで3つのトゥイーンを順にアニメーションさせる

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];
				Starling.juggler.tween(instance, 7, {
					transition:myTransition,
					x:positions[i],
					alpha:ratio,
					scaleX:ratio,
					scaleY:ratio,
					rotation:radians[i],
					onComplete:setTween
				});
				i ^= 1;
			}
		}
	}	
}

第3回スクリプト003は、第4回「StarlingフレームワークのTweenクラスにおける最適化とJugglerクラスの実装」でもお題にしました。その02「Tweenオブジェクトを使い回す」では、ひとつのTweenオブジェクトを使い回すように書直しました(スクリプト001)。インスタンスは使い回した方がエコ、つまりお得だからです。ところがなんと、Juggler.tween()メソッドは最新のエコ家電のように、何もいわなくてもすでにつくったTweenインスタンスは使い回します。なんてお得なんでしょう!TV通販ではありませんが、Starling 1.3でトゥイーンを始めるなら、今すぐ使いたいメソッドです。

05 オブジェクトの位置とそれにかけるフィルタをトゥイーンする

フィルタとJuggler.tween()メソッドをせっかく紹介しましたので、ふたつを組合わせたお題で締めましょう。インスタンスの位置とそれにかけるフィルタを一緒にトゥイーンさせてみます。そう考えたとき、課題はふたつあります。第1に、位置を動かすインスタンスとフィルタは別のオブジェクトだということです。それぞれのオブジェクトに同じ設定のトゥイーンを別々に定めるという手はあります。けれど、このお題では一緒にトゥイーンします。

第2は、フィルタが基本的にメソッドで中身を決め、DisplayObject.filterプロパティに定めなければならないことです。Tweenクラスがトゥイーンするのはオブジェクトのプロパティです。すると、フィルタの設定をどのようにトゥイーンし、DisplayObjectインスタンスにどう適用するかを考えなければなりません。

そこで、フィルタを直にトゥイーンするのでなく、フィルタの設定を変えてDisplayObjectインスタンスに与える処理はメソッドとして書きます。そして、メソッドをTween.onUpdateイベントのハンドラに定めると、トゥイーンが進むたびに呼出されるのです。

Tweenオブジェクト.onUpdate = ハンドラ

すると、フィルタの引数をトゥイーンして、その値をメソッドから用いればよいでしょう。そのために、トゥイーンするオブジェクトは別に設けて、フィルタの引数とアニメーションさせるオブジェクトの座標をともに納めれば、第1の課題も解決です。

そこでまず、トゥイーンはメソッドで(setTween())以下のように定めます。トゥイーンするObjectインスタンス(myObject)には、プロパティとしてフィルタの引数(ratio)とアニメーションさせるインスタンス(instance)のx座標(x)のそれぞれ初期値を加えました。そして、Juggler.tween()メソッドでObjectインスタンスをトゥイーンします。Tween.onUpdateイベントに定めたメソッド(changeStatus())が、アニメーションさせるインスタンスにColorMatrixFilterフィルタを与え、位置を水平に動かします。

private function setTween(halfWidth:Number):void {
	var myObject:Object = {ratio:5, x:instance.x};
	var myFilter:ColorMatrixFilter = new ColorMatrixFilter();
	Starling.juggler.tween(myObject, 7, {
		transition:Transitions.EASE_OUT_BOUNCE,
		x:stage.stageWidth - halfWidth,
		ratio:-1,
		onUpdate:changeStatus,
		onUpdateArgs:[myObject, myFilter]
	});
}

もうひとつ、このスクリプトにはトゥイーンするプロパティとしてTween.onUpdateArgsも加えました。プロパティに配列を与えると、そのエレメントがTween.onUpdateイベントのハンドラに引数として渡されます[*1]。ふたつのエレメントには、トゥイーンするObjectインスタンス(myObject)とColorMatrixFilterインスタンス(myFilter)を加えました。これらはハンドラの引数に渡りますから、ふたつともローカル変数に入れて構わないのです。

Tweenオブジェクト.onUpdateArgs = [onUpdateハンドラの引数]

トゥイーンが進むと呼出されるTween.onUpdateイベントに定めたメソッド(changeStatus())は、カラーマトリクスフィルタと水平座標をアニメーションするインスタンスに与えます。メソッドは第2引数にColorMatrixFilterオブジェクト(myFilter)を受取りますので、ColorMatrixFilter.adjustSaturation()メソッドで彩度を変えます。引数に渡す値は第1引数のオブジェクト(myObject)からプロパティ(ratio)として取出します。

なお、ColorMatrixFilterクラスのカラー調整メソッドは、インスタンスの現在の設定に変化を加えます。そのため、指定した値に設定したいときには、予めColorMatrixFilter.reset()メソッドで初期値に戻さなければなりません。

private function changeStatus(myObject:Object, myFilter:ColorMatrixFilter):void {
	myFilter.reset();
	myFilter.adjustSaturation(myObject.ratio);
	instance.filter = myFilter;
	instance.x = myObject.x;
}

あとは、第1引数のオブジェクト(myObject)からもうひとつの水平座標のプロパティ(x)を取出して、アニメーションするインスタンス(instance)に定めます。これで、ステージのインスタンスは、水平にアニメーションするとともに、彩度の高いカラーからグレースケールに変わっていきます(図009)。Starlingルートクラス(MySprite)全体を、スクリプト002として後に掲げました。

図009■ステージのインスタンスは水平にアニメーションしつつ彩度がグレースケールに変わる
図009上

図009中

図009下

スクリプト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 starling.filters.ColorMatrixFilter;
	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);
			var halfWidth:Number = instance.width / 2;
			instance.pivotX = halfWidth;
			instance.pivotY = instance.height / 2;
			instance.x += halfWidth;
			instance.y = stage.stageHeight / 2;
			addChild(instance);
			setTween(halfWidth);
		}
		private function setTween(halfWidth:Number):void {
			var myObject:Object = {ratio:5, x:instance.x};
			var myFilter:ColorMatrixFilter = new ColorMatrixFilter();
			Starling.juggler.tween(myObject, 7, {
				transition:Transitions.EASE_OUT_BOUNCE,
				x:stage.stageWidth - halfWidth,
				ratio:-1,
				onUpdate:changeStatus,
				onUpdateArgs:[myObject, myFilter]
			});
		}
		private function changeStatus(myObject:Object, myFilter:ColorMatrixFilter):void {
			myFilter.reset();
			myFilter.adjustSaturation(myObject.ratio);
			instance.filter = myFilter;
			instance.x = myObject.x;
		}
	}	
}

[*1] Tween.onUpdateArgsプロパティがTween.onUpdateイベントのハンドラにどのように渡されるかついては、第4回「StarlingフレームワークのTweenクラスにおける最適化とJugglerクラスの実装」の01「イベントをコールバック関数で扱う」でご紹介したTween.advanceTime()メソッドの実装をご参照ください。

 

その他の記事