今回は,ふたつの面を前後に置いて,y軸で水平に回してみたい(図1)。インスタンスの数が増えると,座標の変換だけでなく,その重ね順を考えなければならない。やり方はさまざまで,厳密に処理するほど負荷も増えやすい。いかに単純に扱えるように設計するかが大切だ。
動的に配置したビットマップのふたつの面をマウスポインタに応じて水平に回す
前回の第36回「Matrix3Dクラスの後から加える変換」で作成したスクリプト1に手を加えるかたちで進める。まず準備として,これからのサンプルは面の数が増えていくため,[ライブラリ]のビットマップからBitmapインスタンスを生成して配置する処理は関数にしておこう。前回のスクリプト1は,つぎのようにBitmapインスタンスをつくって,位置決めしていた。
// タイムライン: メイン
// [ライブラリ]のビットマップに[クラス]としてImage0を設定
var mySprite:Sprite = new Sprite();
var myBitmap:Bitmap = new Bitmap(new Image0(0, 0));
var nX:Number = stage.stageWidth / 2;
var nY:Number = stage.stageHeight / 2;
// ...[中略]...
mySprite.x = nX;
mySprite.y = nY;
myBitmap.x = -myBitmap.width / 2;
myBitmap.y = -myBitmap.height / 2;
addChild(mySprite);
mySprite.addChild(myBitmap);
// ...[後略]...
そこで,関数xCreateFace()を以下のように定義する。引数は5つで,第1がビットマップのクラス,第2~4はそのxyz座標,第5が面の水平方向の回転角だ。第5の引数を加えたのは,たとえば4つの面を四方に角柱のように配置するとき,ふたつの側面は90度,後面は180度回す必要があるからだ。この引数は,デフォルト値を0とした(※1)。
// タイムライン: メイン
// [ライブラリ]のビットマップに[クラス]としてImage0を設定
var mySprite:Sprite = new Sprite();
var myBitmap:Bitmap = xCreateFace(Image0, -50, -50, 0);
var nX:Number = stage.stageWidth / 2;
var nY:Number = stage.stageHeight / 2;
mySprite.x = nX;
mySprite.y = nY;
addChild(mySprite);
mySprite.addChild(myBitmap);
// Bitmapインスタンスの面を作成・配置して返す関数
function xCreateFace(myBitmapData:Class, nX:Number, nY:Number, nZ:Number, nRotationY:Number = 0):Bitmap {
var myBitmap:Bitmap = new Bitmap(new myBitmapData(0, 0));
myBitmap.x = nX;
myBitmap.y = nY;
myBitmap.z = nZ;
myBitmap.rotationY = nRotationY;
return myBitmap;
}
処理の内容については,とくに目新しいことはない。あえて補足するなら,関数xCreateFace()の第1引数として,クラスの参照をClass型で受け取っていることだ。このようにクラスの参照からコンストラクタを呼び出して,そのインスタンスがつくれる。[ムービープレビュー]を確かめれば,前回のスクリプト1と同じように,ビットマップを納めたBitmapインスタンスがSpriteインスタンスに加えられて,ステージ中央に置かれる。
さて,準備は整ったので,ふたつの面を回してみよう。といっても,ふたつ別々に扱う必要などない。ふたつともひとつのSpriteインスタンスに入れるのだから,容れ物のSpriteごと回せば済む。つまり,回転の処理は,前回のスクリプト1とまったく変わらない。もっとも,今回は水平にだけ回すので,垂直の処理は省くことになる。
まずは,Bitmapインスタンスの面の位置決めだ。面の数は,後でさらにふたつ増やす。正方形の計4つの面を,Spriteインスタンスの基準点が中心となるように定める。1辺の半分の長さを変数nUnitとすると,Bitmapインスタンスの左上角座標は,前面が(-nUnit, -nUnit, -nUnit),後面は(nUnit, -nUnit, nUnit)となる(図2)。
前回のスクリプト1に手を加え,動的に配置したふたつのビットマップをマウスポインタの位置に応じて水平に回すようにしたのが,以下のスクリプト1だ。前掲関数xCreateFace()を新たに定義し,ふたつのBitmapの面をSpriteインスタンスに納めた。また,DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)のリスナー関数xRotate()は,インスタンスの垂直方向の動きは省いて,マウスポインタの水平座標に応じて水平にのみ回る。
スクリプト1 Sprite内にふたつのビットマップを置いてマウスポインタの位置に応じて水平に回す
// タイムライン: メイン
// [ライブラリ]のビットマップに[クラス]としてImage0とImage1を設定
var mySprite:Sprite = new Sprite();
var nX:Number = stage.stageWidth / 2;
var nY:Number = stage.stageHeight / 2;
var nUnit:Number = 100 / 2;
var frontBitmap:Bitmap = xCreateFace(Image0, -nUnit, -nUnit, -nUnit);
var backBitmap:Bitmap = xCreateFace(Image1, nUnit, -nUnit, nUnit, 180);
var nDeceleration:Number = 0.3;
mySprite.z = 0;
var myMatrix3D:Matrix3D = mySprite.transform.matrix3D;
mySprite.x = nX;
mySprite.y = nY;
addChild(mySprite);
mySprite.addChild(frontBitmap);
mySprite.addChild(backBitmap);
addEventListener(Event.ENTER_FRAME, xRotate);
function xCreateFace(myBitmapData:Class, nX:Number, nY:Number, nZ:Number, nRotationY:Number = 0):Bitmap {
var myBitmap:Bitmap = new Bitmap(new myBitmapData(0, 0));
myBitmap.x = nX;
myBitmap.y = nY;
myBitmap.z = nZ;
myBitmap.rotationY = nRotationY;
return myBitmap;
}
function xRotate(eventObject:Event):void {
var nRotationY:Number = (mouseX - nX) * nDeceleration;
myMatrix3D.appendTranslation(-nX, -nY, 0);
myMatrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
myMatrix3D.appendTranslation(nX, nY, 0);
}
[ムービープレビュー]で確かめると,ふたつの面のBitmapインスタンスそのものは,マウスポインタの位置に応じて水平に回る。しかし,その重ね順が正しく表示されない(図3)。これは,Flash Player 10でz座標が加わっても,インスタンスの重ね順はこれまでと変わらず,親インスタンスの表示リストにおける順序で決まるからだ。したがって,インスタンスのz座標に応じて,重ね順は変えなければならない。
- ※1
- 関数の引数に対するデフォルト値の設定については,第17回「3D風に回転するアニメーション」の2ページ参照。

