ActionScript 3.0で始めるオブジェクト指向スクリプティング

第37回 インスタンスの回転と重ね順

この記事を読むのに必要な時間:およそ 4.5 分

インスタンスの重ね順を定める

面の前後は,z座標値を比べるのが普通だ。しかし今回は,面がふたつで水平にしか回らない。すると,もっと楽な決め方がある。3次元座標空間を真上から見下ろしたyz平面で考えよう。図4は円で表したSpriteインスタンスの中に,前面と後面が置かれている。初めはSpriteインスタンスのy軸回りの角度は0で,文字どおり前面が前にある図4上図)。

視線はz軸の向きだ。Spriteインスタンスのy軸角が反時計回りに-90度で,前後の面ともに視線と平行になる図4中図)。さらに回転すると,後面が手前にくる。逆に,インスタンスが時計回りで90度に至ると両面は視線と並行で図4下図),それを超えれば後面が手前だ表1)。

図4 Spriteインスタンスのy軸回りの角度とふたつの面の位置

回転角: 0°

画像

回転角: -90°

画像

回転角: 90°

画像

表1 Spriteインスタンスのy軸回りの角度と手前に表示される面

Spriteインスタンスのy軸回りの角度手前に表示される面
-180°~-90°後面
-90°~90°前面
90°~180°後面

インスタンスのy軸回りの角度は,DisplayObject.rotationYプロパティで調べられた。すると,つぎのようなifステートメントで面の重ね順を変えればよさそうに思える。この考え方は間違っていない。しかし,y軸による回転角については,特別な仕様があるのだ。

var nRotationY:Number = mySprite.rotationY;
if (nRotationY > 90 || -90 > nRotationY) {
  // 後面を手前に
} else {
  // 前面を手前に
}

3次元空間における回転は,x軸およびz軸については角度が±180度の範囲で定められる。ところが,y軸回りの角度は±90度の範囲になっている※2)。したがって,y軸による回転角が90度を超えたり,あるいは-90度を下回ることがそもそもないのだ。

しかし,それでどうやってy軸で1周の回転が表せるのか。からくりはこうだ。インスタンスをx軸とz軸でともに180度回転する。すると,y軸で180度回したのと同じ裏返しになる図5)。しかし,このときy軸の回転角度は0だ。ここからy軸を±90度の範囲で回転すれば,y軸のみで回した-180~-90度および90~180度に見せかけることができる。

図5 インスタンスをx軸とz軸でともに180度回転する

画像

もとのインスタンス

画像

x軸で180度回転

画像

z軸で180度回転

では問題は,y軸による回転角の見かけが90度を超えたり,-90度を下回ったことをどうやって確かめるかということだ。幸いなことに,まさにy軸の回転角が90度を超えるか-90度を下回ったとき,x軸とz軸による180度の回転が起こる。だから,x軸(またはz軸)の回転角が0度か180度かによって判別すればよい。

インスタンスの重ね順つまり親インスタンスの表示リスト内の位置を変えるのは,DisplayObjectContainer.setChildIndex()メソッド()だった(第24回「インスタンスの管理と配列の並べ替え」4ページ参照)。また,表示リスト内のインスタンスの数は,DisplayObjectContainer.numChildrenプロパティで調べられる。つぎのスクリプト2には,面のインスタンスの重ね順を正しく定める関数xSetOrder()が新たに定義された。

スクリプト2 マウスポインタの位置に応じて水平に回したふたつの面の重ね順を設定する

// タイムライン: メイン
// [ライブラリ]のビットマップに[クラス]として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);
  xSetOrder();
}
function xSetOrder():void {
  var nTop:uint = mySprite.numChildren - 1;
  if (mySprite.rotationX > 90) {   // x軸で180度回転していたら
    mySprite.setChildIndex(backBitmap, nTop);
  } else {
    mySprite.setChildIndex(frontBitmap, nTop);
  }
}

関数xSetOrder()は,リスナー関数xRotate()から呼び出される。表示リスト内のインデックスは0から始まるので,最前面のインスタンスのインデックスはDisplayObjectContainer.numChildrenプロパティの値から1差引いた整数になる。そして,x軸で180度回転しているかどうかを判別して,正しいインスタンスを最前面に置いている。

なお,x軸回りの角度は0度または180度をとるものの,若干の誤差を含むことがある。そのため,上記スクリプトのif条件では間の90度を境にして切り分けた。[ムービープレビュー]を確かめると,インスタンスの重ね順はSpriteインスタンスの回転角度に応じて正しく入れ替わる図6)。

図6 インスタンスの重ね順が正しく変わる

画像 画像

次回は,さらに回す面の数を増やし,重ね順を決めるもう少し厳密な方法について説明したい。

※2

第34回3次元空間における回転で確かめたように,DisplayObject.rotationYプロパティに直接代入すれば,±90度の範囲はおろか±180度を超える値も設定できた。その場合であれば,DisplayObject.rotationYプロパティの値が90度を超えるか,-90度より小さいかという判定を加えることもできる。

2010年8月2日に開かれた「ActionScript 3.0による 三次元表現 in Apple Store, Ginza」では,そのような例も紹介した。なお,セミナーの映像が公開されている。3次元空間の扱いについて,基本的な考え方を45分で解説した。これまでの復習だけでなく,これからの予習となる内容も若干含まれている。興味があれば,ぜひご覧いただきたい。

今回解説した次のサンプルファイルがダウンロードできます。

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入