TweenとTransition

時が経つのは速いもの

 さて標準コンポーネントも一通り使ってみた事なので、次はやはりそれを活用してみたい。
 てなわけで、当サイトの2大テーマのひとつであるところのゲームを作ってみる事にする。
 締め切りは3月中。
 Flashで比較的作りやすいと評判の「脱出ゲーム」を作ってみる事にする。

 とここまで書いていたんだけど、皆さんご存知の通り今はもう夏。締め切りも何もあったものではない。

 そこで(どこで?)Flashといったらアニメーション。ActionScriptでアニメーションしてみたい。

さて、アニメーションですが

 なんか、Flash8のころからアニメーション用のTweenってクラスってあったみたい。
 私はFlash MX(6)から飛んでFlash CS3(9)へという流れでやっているので、ActionScript2.0がすっぽり抜けている。
 そんなわけで、まずは他の言語でも使い回せる、アニメーションのド基本をやってみる。ただし、画面書き換えはTimerイベントではなくてFlashらしくenterFrameで。

 ところで、ActionScript3.0ってプライベートクラスが作れるんですよね、packageの外に書けばOK。簡単。
 ただ、importを別に書かなきゃいけないのは面倒。あと、頭にprivateって書く必要は無い、というか書いちゃダメ。

//!-- UTF8
package
{
	import flash.display.MovieClip;
	import flash.events.Event;

	public class BallAnime extends MovieClip
	{
		private var b:Ball;

		function BallAnime()
		{
			b = new Ball();
			b.x = 100;
			b.y = 100;
			addChild( b );
			
			addEventListener( Event.ENTER_FRAME, enterFrameHandler );
		}
		
		private function enterFrameHandler( e:Event ):void
		{
			b.x += 1;
		}
	}
}

import flash.display.Graphics;
import flash.display.Sprite;
class Ball extends Sprite
{
	public function Ball()
	{
		var g:Graphics = graphics;
		g.beginFill( 0xff0000 );
		g.drawCircle( 0, 0, 16 );
	}
}

 横にじんわり動きます!!

 Σc ' _' )  < 思った以上にしょぼかったので、勢いでごまかそうとしてるな…
 $ σ_σ$  < まぁ、いいんじゃない…たまには勢いで凄いって勘違いする人もいるかもよ

 今この瞬間、勘違いする人がいなくなったんですが…

fl.transitions.Tween

 で、fl.transitions.Tweenですよ。
 TweenのコンストラクタにアニメーションさせるDisplayObjectと、アニメーションのための関数を渡す。
 で、その関数は自分でも作れるけど、motion.easingパッケージの中に色々用意してある。試しにBounce.easeOutを使ってみる。加速しつつ移動して終点のところで跳ねる、という動きだ。

//!-- UTF8
package {
	import flash.display.MovieClip;
	import fl.transitions.Tween;
	import fl.motion.easing.Bounce;
	import fl.motion.Tweenables;

	public class BallTween extends MovieClip {
		private var b:Ball;

		function BallTween() {
			b = new Ball();
			b.y = 100;
			addChild( b );
			
			new Tween( b, Tweenables.X, Bounce.easeOut ,100, 400,20 );
		}
	}
}

import flash.display.Graphics;
import flash.display.Sprite;
class Ball extends Sprite
{
	public function Ball()
	{
		var g:Graphics = graphics;
		g.beginFill( 0xff0000 );
		g.drawCircle( 0, 0, 16 );
	}
}

 Tweenに渡す関数(上のコードでBounce.easeOutの部分)は以下のような感じに作ればいいようだ。

private function tweenMethod( t:Number, b:Number, c:Number, d:Number ):Number
{
	/**
	渡された以下の値を元にして、返す値を決定する。
	t : 現在時間(time) 0-d の間の現在地を示す値。アニメーション中は、この値しか変化しない。
	b : 開始点(begin value)
	c : 変化量(change value) 初期値に加算される値。つまり終点は b + c となる。
	d : 全体の時間(duration)
	 */

	return  b +  c *  ( t / d ); // これが一番単純なLinearの中味( 予想 )
}

 このコードでは使ってないけど、生成したtweenインスタンスのメソッドでアニメーションを止めたり巻き戻したり、イベント(fl.transitions.TweenEvent)を使ってアニメーションが終了したところで次の処理を開始したり、色々できるようだ。
 さらに言うと、別に画像オブジェクトじゃなくても、どんなオブジェクトのどんなプロパティであってもトゥイーンできるようだ。

 まとめると「Tweenオブジェクトは、2数値間で目標時間内でプロパティを変化させる」ということと理解して良いようだ。
 用意する要素は以下の通り。

 んで、開始・アップデート・停止・再開・終了などのイベントを発生させるので、それらを使った制御もできる。
 さっきのスクリプトはTweenを生成したあと放りっぱなしだったけど、以下のようにちゃんとTweenのインスタンスを拾っておけば、addEventListenerできる。

		private var t:Tween;
		...
			t = new Tween( b, Tweenables.X, Bounce.easeOut ,100, 400,20 );

			t.addEventListener( TweenEvent.MOTION_CHANGE, motionHandler );
			t.addEventListener( TweenEvent.MOTION_FINISH, motionHandler );
			t.addEventListener( TweenEvent.MOTION_LOOP, motionHandler );
			t.addEventListener( TweenEvent.MOTION_RESUME, motionHandler );
			t.addEventListener( TweenEvent.MOTION_START, motionHandler );
			t.addEventListener( TweenEvent.MOTION_STOP, motionHandler );
		}
		private function motionHandler( e:TweenEvent ):void
		{
			trace( "Event :", e.type );
		}

 わりとTweenは分かりやすいけど、複雑な事をやりたくなったら力不足な感は否めない。
 そういう人は、Tweenerクラスとか使うのが良いらしい。私はまだ使った事がない。そりゃそーですわな、標準のTweenだって使うの初めてなんだから。
 ちなみにTweenerは、もう時代遅れだということで開発終了しているようなんだけど、それって「枯れてる」って事だから、わりと良い事のような気がする。あとで使ってみよう。

fl.transitions.TransitionManager

 おつぎは、fl.transitions.TransitionManager
 ダサイ映画が場面転換に多用する傾向にあるトランジションです。「スターウォーズ」は好きですけど、トランジションはダサイと思います。

 あらかじめステージに"b"ってインスタンス名のムービークリップを用意して、以下のドキュメントクラスでもって実行。

//!-- UTF8
package {
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import fl.transitions.*;
	import fl.transitions.easing.*;

	public class BlindsTransition extends MovieClip {
		public var b:MovieClip;

		function BlindsTransition() {
			stage.addEventListener( MouseEvent.CLICK, clickHandler );
		}
		private function clickHandler( e:MouseEvent ):void
		{
			var tr:Object =
			{
				type:Blinds,
				direction:Transition.IN,
				duration:0.5,
				easing:None.easeNone,
				numStrips:20,
				dimension:1
			};
			TransitionManager.start( b, tr );
		}
	}
}

 TransitionManager.start()でトランジションが実行されるんだけど、戻り値のfl.transitions.Transitionを見ても、終了を知らせるイベントとかないよーな…。どないせいっちゅん。
 と、良く読むと"transitionInDone" イベントまたは "transitionOutDone"イベントで、終了が監視できるとある。
 あーうー、定数の定義もなけりゃ、そもそもイベントとしてASDocに公開してないとかどういう了見なんだろう…。次回のバージョンアップでちゃんと定義される事を期待したい。
 とりあえず、リテラルで直書きしてイベントを受けてみる。
 Transition.INの場合の"transitionInDone"と、Transition.OUTの場合の"transitionOutDone"と、終了イベントが違うんだけど、…分ける意味がよく分からない。それより開始イベントとアップデートイベントはないのか?

		private var t:Transition;
		...
			t = TransitionManager.start( b, tr );

			t.addEventListener( "transitionInDone", motionHandler );
			t.addEventListener( "transitionOutDone", motionHandler );
		}
		private function motionHandler( e:Event ):void
		{
			trace( "Event :", e.type );
		}

 あと、このトランジションってMovieClipじゃないと動かない。Spriteはもちろん単純にMovieClipを継承したクラスでも動かなかった。
 なんだか"__TransitionManager"とかゆープロパティが必要らしい…どゆこと?
 ともかく、Transitionは作りかけ感あふるるクラスである事は確か。

 ところで、イージングの関数を提供するパッケージには、fl.motion.easingと、fl.transitions.easingが存在しているんだけど、実のところほぼ中味は一緒のようだ。
 同じ名前のクラスを入れ替えても動く。作ってるクラスがmotionパッケージ使っているか、transitionsパッケージ使っているかだけで使い分けてよさげ。

次回の宿題

 あと、アニメーションのためのクラスというとfl.motion.Motionがあるんだけど、これはけっこう大掛かりなクラスのようなので、今回はスルー。
 次回への課題とする。

 それはそうと、アニメーション用のクラスってFlex用はFlex用で別にあるんだよねー。マジめんどくさい。なんでこんなおかしな事になっているのか。
 Flash CS3とかのFlash IDE系と、Flash Builder・Flex SDKのFlex系で、もはや別言語の様相。
 Flex全然やってないし、Flash(ActionScript3.0)リファレンス概要からは、Flexの項目なくしちゃおうかなぁ。メンテしてないし。

 今日はここまで。


2011-07-09