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

第9回 簡単3Dから始める奥行きのある話 (1)

Flashで3Dと言えばPapervision3Dなどのライブラリに目が行ってしまいがちですが、Flashには3Dを扱う機能が標準で用意されています。しかし、どちらにせよ3Dは難しいと途中で投げ出してしまった人も少なからずいることでしょう。ちょっとでもいいから3Dを使いたいなあと思っているなら、まずは簡単なことから始めてみましょう。

サンプルファイル : edge_oshige_09_sample_fla.zip (45KB)

Y軸を回転させる

CS4に3D機能が搭載されたとき、まず最初に試したのは軸の回転でしょう。軸の回転?と聞いてピンと来なくてもサンプルを見れば一目瞭然。Y軸回転なら、竹とんぼを両手に挟んで回す回転と同じです。
表示オブジェクトのY軸の回転角度はrotationYプロパティです。使い方はrotationプロパティと同じです。例えば、次のようにムービークリップインスタンスedge_mcのrotationYに連続的に数値を加算するだけでイメージがY軸で回転します。回転するイメージは3Dらしく投影法で変形し、裏返しになるとイメージが反転します。rotationX、rotationZでの回転も同じように考えます。rotationXでの回転は鉄棒につかまって前回りをする回転、Z軸での回転は当たりを書いたダーツの的を手で回す回転です。

[sample] rotationY.fla
ムービークリップインスタンスをY軸で3D回転させます。

addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//Y軸回転
function enterFrameHandler(e:Event):void{
	edge_mc.rotationY += 3;
}


fig1 ムービークリップインスタンスがY軸で3D回転します

なお、rotationYの回転はXYZ軸の座標軸をY軸で回転させるので、Y軸の回転と同時にXZ軸も回っています。Y軸の周りを飛ぶように回る移動とは違います。

z座標で奥行きを利用する

3D座標を扱うということは、当然ながらxy座標に加えてz座標があります。z座標はステージに矢を突き刺したように手前から奥へと進む座標です。Flashのステージに置いてあるインスタンスはz座標の値が0の状態で、値を大きくするとインスタンスはステージよりも奥へと遠ざかってどんどん小さくなります。逆に値をマイナスにするとステージよりも手前にある位置になりサイズが大きくなります。
次の例はedge_mcがz座標3000の遠い位置から手前へ飛んでくるアニメーションです。zの値を10ずつ減算すると同時にrotationXの値を5ずつ加算しているので、edge_mcは前転しながらどんどん近づきます。z座標の値が-500より小さな値になり、画面をふさぐほど近づいて大きくなったならば、zの値を3000に戻して再び遠くから出てくるようにします。また、遠くの位置では霞むようにz値に合わせてアルファ値も計算しています。

[sample]spacetrip .fla
遠くから前転しながら近づいてくる

addEventListener(Event.ENTER_FRAME, enterFrameHandler);
edge_mc.alpha = 0;
edge_mc.z = 3000;
//遠くから回転しながら手前へ飛んでくる
function enterFrameHandler(e:Event):void {
	if (edge_mc.z < -500) {
		edge_mc.alpha = 0;
		//遠くへ戻す
		edge_mc.z = 3000;
	} else {
		edge_mc.alpha = (3000-edge_mc.z)/3000;
		//手前に飛んでくる
		edge_mc.z-=10;
	}
	//前回りする
	edge_mc.rotationX+=5;
}


fig2 ムービークリップインスタンスが遠くから回転しながら飛んできます

3D空間でのインスタンスの重なり

今のサンプルを発展させて、流星群のようにたくさんのedgeの文字が飛んでくるサンプルを作ってみましょう。次のSpaceEdgeクラスは、edgeと書いてあるオブジェクトが遠くから手前へ飛んでくるインスタンスを1個だけ作るクラスです。インスタンスが手前へ飛んでくる部分は先のスクリプトと基本的に同じです。zの値を徐々に小さくすれば手前へ近づき、rotationXの値を加算すれば手前に回転します。SpaceEdgeクラスのインスタンスをたくさん作れば、edgeの文字が流星群のように飛んでくるムービーになります。

[sample] spaceEdge.fla


fig3 ムービークリップインスタンスが流星群のようにたくさん飛んできます

[sample] SpaceEdge.as
遠くから手前へ飛んでくるインスタンスを作るSpaceEdgeクラス

package {
	import flash.display.MovieClip;
	import flash.events.Event;

	public class SpaceEdge extends MovieClip {
		function SpaceEdge(x:Number,y:Number,z:Number) {
			this.x = x;
			this.y = y;
			this.z = z;
			this.alpha = (3000 - z) / 3000;
			rotationX = Math.random() * 360;
			addEventListener(Event.ADDED_TO_STAGE,addToStageHandler);
		}
		//ステージに追加されたら実行する
		protected function addToStageHandler(eventObj:Event):void {
			addEventListener(Event.ENTER_FRAME,enterFrameHandler);
		}
		//毎フレーム実行する
		protected function enterFrameHandler(e:Event):void {
			if (z < -500) {
				alpha = 0;
				x = Math.random() * stage.stageWidth * 4 - stage.stageWidth;
				y = Math.random() * stage.stageHeight * 4 - stage.stageHeight;
				//遠くへ送る
				z = 3000;
				//最背面に移動する
				parent.setChildIndex(this,0);
			} else {
				alpha = (3000 - z) / 3000;
				//手前に近づいてくる
				z -= 10;
			}
			//前回りの回転
			rotationX+=2;
		}
	}
}

SpaceEdgeクラスから複数のインスタンスを作ってステージに配置するスクリプトはフレームアクションに書いています。必要な個数だけインスタンスを作ってステージに追加するだけなので簡単に思えますが、ここで大事なポイントがあります。それはインスタンスの重なりの問題です。z座標が大きいからと言って、表示オブジェクトが下の重なりになるということはないのです。

インスタンスの位置が3D空間でばらつくようにxyzの座標の値をランダムに決めた場合、近くの物が遠くの物よりも手前の重なりになるようにするには、z座標を比較してインスタンスの重なりを決める必要があります。これを解決する方法はいくつかありますが、ここでは最も簡単な方法をとります。インスタンスの個数分のランダムなz座標の値を作って配列に入れ、それをソートして大きな順に並べ替えておきます。インスタンスを作成する際に配列から値を順に取り出してz座標に指定すれば、遠くにある物から順に作ることになるので、そのままステージに追加すればよいことになります。

[sample] spaceEdge.fla
SpaceEdgeクラスで30個のインスタンスを作り、z座標でソートして重ねる

//-500~3000の間のランダムな値を30個作る
var num:int = 30;
var zlist:Array = new Array();
for (var i:int=0; i<num; i++) {
	zlist.push(Math.random() * 3500-500);
}
//値を大きな順に並べ替える
zlist.sort(Array.DESCENDING | Array.NUMERIC);
//x,y,z座標を指定してインスタンスを作る
for (var j:int=0; j<num; j++) {
	var x3:Number = Math.random() * stage.stageWidth*4- stage.stageWidth;
	var y3:Number = Math.random() * stage.stageHeight*4- stage.stageHeight;
	var z3:Number = zlist[j]
	addChild(new SpaceEdge(x3,y3,z3));
}

あと1つ忘れてはならないのは、インスタンスが手前まで飛んできて再び遠くの位置に戻す場合です。このときにも重なりが変わるので、重なりも一番下に再設定します。SpaceEdgeクラスのenterFrameHandler関数にそのスクリプトが書いてあります。


 //遠くへ送る
 z = 3000;
 //最背面に移動する
 parent.setChildIndex(this,0);

さて、今回はここまでです。
次回は写真をクリックで裏返す、「ちょっとした裏ワザ!」を紹介します。お楽しみに。

 

関連情報


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

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

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