大重美幸の「これ見落としてませんか? ActionScript 3.0」

最終回 簡単3Dから始める奥行きのある話 (2)

XYZ軸を回転させるだけの3Dアニメーションでも、コンテンツがリッチに生まれ変わります。今回はクリックすると裏返って止まるインタラクティブな操作を考えてみましょう。画面を裏返すだけですが、トランプの表裏、写真の裏に撮影データが書いてある、画面を裏返すと設定画面になるなどのいろんな活用法が思い付きます。

サンプルファイル : edge_oshige_10_sample_fla.zip (399KB)

クリックした写真を裏返す

前回、「edge」と書いたムービークリップインスタンスをY軸で回転させる例を示しました。同じように写真をY軸で回転させると、写真が3D空間で回転して見えます。次のサンプルでは写真をクリックするとくるりと反転して止まります。イメージをY軸で回転させるとイメージが反転している点にも注意して下さい。

[sample] turnover.fla


クリックすると写真が反転して、裏面の絵が表示されます

このサンプルでは、インスタンスを回転させるアニメーションをTweenクラスを利用して行っています。次のように実行すれば、cardのrotationYの値が0度から180度まで1秒間でイージングします。イージング関数にはNone.easeInを指定しているのでcardは等速で回転します。


tw = new Tween(card,"rotationY",None.easeIn,0,180,1,true);

回転にイージングを利用するところもミソですが、このサンプルの最初のポイントは、回転させるムービークリップの表と裏のイメージを入れ替えるタイミングです。試すとわかるように表と裏のイメージが切り替わるのは180度回転して完全に裏返ってしまったときではなく、ちょうど半分まで回転して90度を過ぎたときです。

Tweenクラスのイージングを行うと、値が変化するたびにTweenEvent.MOTION_CHANGEイベントが発生します。これを利用してmotionChangeHandler関数を実行し、そのときのrotationYの値をチェックします。rotationYが90より大きいときは裏面、小さいときは表面なので、photoCardにフレームomoteとフレームuraを作っておきフレーム移動を行ってイメージを切り替えれば、回転に合わせて写真が裏返るように見えます。

ただし、ここで1つ注意しなければならないことがあります。それは、裏面のイメージは反転イメージにしておくということです。rotationYが90度を超えるとイメージが反転して表示されます。そこで最初から反転イメージにしておけば、裏返ったときに正しく表示されるというわけです。

[sample] turnover.fla
写真をクリックすると反転して裏面を表示する

import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.transitions.easing.*;

var tw:Tween;
photoCard.stop();
photoCard.addEventListener(MouseEvent.CLICK, clickHandler);
//クリックイベント
function clickHandler(e:MouseEvent):void {
	var card:MovieClip = e.target as MovieClip;
	//現在の回転角度から回転方向を決める
	if (card.rotationY == 0) {
		tw = new Tween(card,"rotationY",None.easeIn,0,180,1,true);
	} else {
		tw = new Tween(card,"rotationY",None.easeIn,180,0,1,true);
	}
	//イベントリスナーの設定
	tw.addEventListener(TweenEvent.MOTION_CHANGE, motionChangeHandler);
	tw.addEventListener(TweenEvent.MOTION_FINISH, motionFinishHandHandler);
	card.removeEventListener(MouseEvent.CLICK, clickHandler);
}
//トゥイーン完了イベント
function motionFinishHandHandler(e:TweenEvent):void {
	var card:MovieClip = e.target.obj as MovieClip;
	card.addEventListener(MouseEvent.CLICK, clickHandler);
}
//トゥイーン経過イベント
function motionChangeHandler(e:TweenEvent):void {
	var card:MovieClip = e.target.obj as MovieClip;
	if (card.rotationY > 90) {
		card.gotoAndStop("ura");
	} else {
		card.gotoAndStop("omote");
	}
}

omote ura
fig1 フレームomoteに表面、フレームuraに裏面を作ります。裏面はイメージを反転させておく必要があります

裏面のイメージをスクリプトで反転させる

今紹介したサンプルの場合は裏面のイメージを反転させておく必要があります。写真や絵は簡単に反転イメージを作れますが、テキストフィールドはそうはいきません。先のサンプルでは静止テキストを分解して反転イメージを作っていました。
そこで次のサンプルでは、表示するイメージをビットマップデータに変換し、表面イメージと裏面イメージをあらかじめ作成しています。裏面イメージは反転させて作る必要がないように、ビットマップデータを反転させます。テキストフィールドもビットマップデータに写すので回転の最中でも文字が消えません。

[sample] turnover2.fla


クリックすると写真が反転して、裏面の絵が表示されます。動作としては先のサンプルと同じです

まずは表面イメージと裏面イメージを作りましょう。先のサンプル同様にムービークリップphotoCardにフレームomoteとフレームuraのキーフレームを作り、omoteには写真、uraには裏面の絵を作ります。先のサンプルでは文字を分解して裏返しておきましたが、今回はテキストフィールドのままで構いません。なお、先のサンプルではイメージのセンターが座標の中心になるように作りましたが、今回は左上角が座標の中心になるように作ります。

表面 裏面
fig2 表面と裏面のキーフレームを作ります。左上角が座標の中心になるように写真や絵を配置します。
裏面のイメージを反転させておく必要がありません

スクリプトでは表面と裏面のキーフレームからビットマップデータを作ります。まず、縦横サイズがphotoCardと同じ大きさの表面用のビットマップデータbmd_omoteを作ります。次にphotoCardをフレームomoteに移動し、draw()を実行してbmd_omoteに表面のイメージを描画します。


//表面用のbitmapdata
var bmd_omote:BitmapData = new BitmapData(photoCard.width,photoCard.height);
photoCard.gotoAndStop("omote");
//表面のイメージを転写する
bmd_omote.draw(photoCard);

続いて裏面です。裏面用のビットマップデータbmd_uraと作業用のビットマップデータbmd_tmpを用意します。まず、フレームuraに移動し、draw()を実行して作業用のビットマップデータbmd_tmpに裏面のイメージを描画します。ビットマップデータにdraw()したことで、テキストフィールドの文字もビットマップとして写し取られます。

さて、ここからがポイントです。この作業用ビットマップデータのイメージを反転させて裏面のビットマップデータbmd_uraに写します。描画に使うメソッドはdraw()と同じですが、変形マトリックスmtrxをオプションで指定してイメージを反転させます。イメージを反転させる簡単な方法はスケールを-1にすればいいので、mtrx.scale(-1,1)を実行して反転させます。しかし、イメージは(0,0)の位置を基準にして裏返るので画角の外に出てしまいます。そこでmtrx.translate(photoCard.width,0)を実行してイメージを元の位置に戻します。


//イメージを反転させた裏面イメージを作る
var mtrx:Matrix = new Matrix();
mtrx.scale(-1,1);
mtrx.translate(photoCard.width,0);
//反転した裏面イメージを転写する
bmd_ura.draw(bmd_tmp,mtrx);

これで表面と裏面のビットマップデータが用意できました。次にこのビットマップデータをステージに表示します。ビットマップデータは表示オブジェクトではありません。ビットマップデータを表示するためのビットマップを作って表示します。


//表面イメージのビットマップを作る
var bmp:Bitmap = new Bitmap(bmd_omote);

ステージに表示して回転させるだけならばこのbmpをステージに追加すれば終わりですが、クリックで反転するようにするには問題があります。ビットマップはクリックイベントを受け取らないのです。そこでムービークリップを作り、ビットマップを子オブジェクトとして追加します。ムービークリップインスタンスにマウスイベントハンドラを設定すればクリックで反転する仕組みを組み込めます。
あとは回転に合わせて表と裏のビットマップデータを差し替えるだけです。ビットマップbmpのビットマップデータは、bitmapDataプロパティを設定するだけで入れ替えることができます。


if (card.rotationY > 90) {
    //裏面イメージに変更
    bmp.bitmapData = bmd_ura;
} else {
    //表面イメージに変更
    bmp.bitmapData = bmd_omote;
}

以上でスクリプトの説明は終わりです。Bitmapクラス、BitmapDataクラスに慣れてない人には少し難しかったかもしれませんが、ビットマップを扱えるようになると可能性が広がります。今回の3Dの話と合わせてぜひ勉強してみてください。

[sample]turnover2 .fla
表面と裏面イメージをビットマップデータで処理する

import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.transitions.easing.*;
var tw:Tween;
/*
* 表面、裏面のビットマップデータの準備
*/
var photoCard:MovieClip = new photo();
//表面用のbitmapdata
var bmd_omote:BitmapData = new BitmapData(photoCard.width,photoCard.height);
photoCard.gotoAndStop("omote");
//表面のイメージを転写する
bmd_omote.draw(photoCard);
//裏面用のbitmapdata
var bmd_ura:BitmapData = new BitmapData(photoCard.width,photoCard.height);
//作業用のbitmapdata
var bmd_tmp:BitmapData = new BitmapData(photoCard.width,photoCard.height);
photoCard.gotoAndStop("ura");
bmd_tmp.draw(photoCard);
//イメージを反転させた裏面イメージを作る
var mtrx:Matrix = new Matrix();
mtrx.scale(-1,1)
mtrx.translate(photoCard.width,0);
//反転した裏面イメージを転写する
bmd_ura.draw(bmd_tmp,mtrx);

//表面イメージのビットマップを作る
var bmp:Bitmap = new Bitmap(bmd_omote);
bmp.x=-photoCard.width/2;
bmp.y=-photoCard.height/2;
//ムービークリップにビットマップを表示する
var card:MovieClip = new MovieClip();
card.addChild(bmp);
card.x=stage.stageWidth/2;
card.y=stage.stageHeight/2;
addChild(card);
card.addEventListener(MouseEvent.CLICK, clickHandler);

//クリックイベント
function clickHandler(e:MouseEvent):void {
	var card:MovieClip = e.target as MovieClip;
	//現在の回転角度から回転方向を決める
	if( card.rotationY==0){
		tw = new Tween(card,"rotationY",None.easeIn,0,180,1,true);
	}else{
		tw = new Tween(card,"rotationY",None.easeIn,180,0,1,true);
	}
	//イベントリスナーの設定
	tw.addEventListener(TweenEvent.MOTION_CHANGE, motionChangeHandler);
	tw.addEventListener(TweenEvent.MOTION_FINISH, motionFinishHandHandler);
	card.removeEventListener(MouseEvent.CLICK, clickHandler);
}
//トゥイーン完了イベント
function motionFinishHandHandler(e:TweenEvent):void {
	var card:MovieClip = e.target.obj as MovieClip;
	card.addEventListener(MouseEvent.CLICK, clickHandler);
}
//トゥイーン経過イベント
function motionChangeHandler(e:TweenEvent):void {
	var card:MovieClip = e.target.obj as MovieClip;
	if (card.rotationY > 90) {
		//裏面イメージに変更
		bmp.bitmapData = bmd_ura;
	} else {
		//表面イメージに変更
		bmp.bitmapData = bmd_omote;
	}
}

さて、連載「これ見落としてませんか? ActionScript 3.0」は10回を終了し、今回が最終回です。
長い間、ご愛読ありがとうございました。

関連情報


大重美幸氏写真大重美幸
(おおしげよしゆき)

日立情報システムズ、コミュニケーションシステム研究所を経て独立。株式会社ロクナナ顧問。執筆、講師、ソフトウェア開発を行う。趣味はサーフィンとジョギング。茅ヶ崎在住。著書は約55冊。
twitter : @oshige@as3note

近著:Adobe Flash CS4 詳細!ActionScript 3.0入門ノート[完全改訂版]ActionScript3.0辞典[FlashPlayer10/9対応] ブラウザで無料ではじめるActionScript 3.0 - it's a wonderfl world