サイトトップ

Director Flash 書籍 業務内容 プロフィール

ActionScript 3.0 for 3D

□Samples サンプルをクラスで定義する

SPL-02 立方体のインスタンスをマウスポインタの位置に応じて回す
つぎに、Matrix3Dクラスにより、立方体のインスタンスをマウスポインタの位置に応じて回すサンプルです(再掲図03-017)。前掲スクリプト04-011がお題となります。

図04-028■立方体のインスタンスがマウスポインタの位置に応じて水平・垂直に回転する(再掲)
見える3つの面だけの重ね順が定められ、隠れる裏側の面は表示していない。

スクリプト04-011のサンプルと同じように、[ライブラリ]には6面分の正方形のビットマップを納め、それぞれには[クラス]としてImage0〜Image5を設定しておきます(図SPL-006)。

図SPL-006■[ライブラリ]に6面分の正方形のビットマップを納める
6つのビットマップには、それぞれには[クラス]としてImage0〜Image5を設定しておく。

クラスでつくった立方体Spriteをタイムラインから操作する
クラスはふたつで組立てます。ひとつは、立方体のSpriteインスタンスをつくり、その表示をコントロールするクラスです。もうひとつのクラスは、立方体のインスタンスに6つの面や位置を定め、アニメーションの指示も行います。ちょうど前者がMovieClipインスタンスで後者はタイムラインのような位置づけで、タイムラインがMovieClipインスタンスの配置やアニメーションを扱い、MovieClipインスタンスはその結果を表示することになる訳です。

先に、立方体のインスタンスをつくるクラスCubeから定義します。CubeはSpriteのサブクラスです。このクラスCubeをフレームアクションから呼出すと、つぎのスクリプトSPL-004のようになります。

スクリプトSPL-004■クラスCubeから立方体を生成してアニメーションさせるフレームアクション
    // フレームアクション
    // [ライブラリ]の6つのビットマップにそれぞれ[クラス]としてImage0〜Image5を設定
  1. var nX:Number = stage.stageWidth / 2;
  2. var nY:Number = stage.stageHeight / 2;
  3. var nDeceleration:Number = 0.2;
  4. var frontBitmap:Bitmap = new Bitmap(new Image0(0, 0));
  5. var backBitmap:Bitmap = new Bitmap(new Image1(0, 0));
  6. var leftBitmap:Bitmap = new Bitmap(new Image3(0, 0));
  7. var rightBitmap:Bitmap = new Bitmap(new Image2(0, 0));
  8. var topBitmap:Bitmap = new Bitmap(new Image4(0, 0));
  9. var bottomBitmap:Bitmap = new Bitmap(new Image5(0, 0));
  10. var mySprite:Cube =
    new Cube(frontBitmap, backBitmap, leftBitmap, rightBitmap, topBitmap, bottomBitmap);
  11. addChild(mySprite);
  12. mySprite.x = nX;
  13. mySprite.y = nY;
  14. addEventListener(Event.ENTER_FRAME, xRotate);
  15. function xRotate(eventObject:Event):void {
  16.   var nRotationY:Number = (mouseX - nX) * nDeceleration;
  17.   var nRotationX:Number = (mouseY - nY) * nDeceleration;
  18.   mySprite.rotate(nRotationY, nRotationX);
  19. }

基本的には、前掲スクリプト04-011からクラスCubeに移した処理の残りになります。ステートメントもほとんど同じで、違うのはふたつの点です。

第1は、スクリプトSPL-004第10行目のCubeコンストラクタの呼出しです。引数として6つの面のBitmapインスタンスを、前後左右および上下の順に渡しています。第2に、DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)のリスナー関数xRotate()です(スクリプト第15〜19行目)。マウスポインタの座標から求めたy軸回りとx軸回りの回転角を、Cubeクラスのメソッドrotate()にふたつの引数として渡しています。

これで、クラスCubeのコンストラクタに渡す引数、および備えるべきメソッドrotate()とその引数がわかりました。すると、クラスCubeに定義する処理内容の大枠も定まります。立方体のインスタンスをつくって、その表示をコントロールするクラスCubeの定義は、後に掲げるスクリプトSPL-005のとおりです。その要点を抜粋しながら確かめていきましょう。

まず、以下に抜出したのはコンストラクタメソッドCube()です(スクリプト第16〜27行目)。前述のとおり、メソッドは6つの面のインスタンスを引数として受取ります(スクリプト第16行目)。それらのデータ型は、DisplayObjectにしています。つまり、立方体の面にできるのは、Bitmapインスタンスにかぎりません。タイムラインにアニメーションをつくり込んだMovieClipインスタンスやFLVビデオなど、DisplayObjectを継承するインスタンスなら立方体の面に指定できるのです。

さまざまなインスタンスが立方体の面になるとすれば、その1辺の大きさをCubeクラス側で決めてしまうのも融通が利きません。そこで、コンストラクタメソッドの第7引数には、1辺の長さを数値で指定できるようにしました。デフォルト値は100ピクセルです。ただ、今の段階では、まだ面のサイズを変更する処理は加えません。

  1.   public class Cube extends Sprite {
  2.     private var unit:Number;
  3.     private var frontFace:Sprite;
  4.     private var backFace:Sprite;
  5.     private var leftFace:Sprite;
  6.     private var rightFace:Sprite;
  7.     private var topFace:Sprite;
  8.     private var bottomFace:Sprite;
  9.     private var myMatrix3D:Matrix3D;
  10.     public function Cube(front:DisplayObject, back:DisplayObject, left:DisplayObject, right:DisplayObject, top:DisplayObject, bottom:DisplayObject, edge:Number = 100) {
  11.       unit = edge / 2;
  12.       z = 0;
  13.       myMatrix3D = transform.matrix3D;
  14.       frontFace = createFace(front, 0, 0, -unit);
  15.       backFace = createFace(back, 0, 0, unit, 180, 0);
  16.       leftFace = createFace(left, -unit, 0, 0, 90, 0);
  17.       rightFace = createFace(right, unit, 0, 0, -90, 0);
  18.       topFace = createFace(top, 0, -unit, 0, 0, -90);
  19.       bottomFace = createFace(bottom, 0, unit, 0, 0, 90);
  1.     }
  1.   }

コンストラクタメソッド内で行っているのは、6面を立方体に組立てる処理と初期設定です。基本的な内容は、前掲スクリプト04-011と異なりません。ただ、各面のSpriteインスタンスをプロパティ(スクリプト第9〜14行目)としてもつことにしました。これは、後あと面のインスタンスを入替えたり、設定を変えることができるようにするためです。もっとも、今回はとくにそのような処理は加えません。

つぎに、Cubeクラスのメソッドは、まず立方体のインスタンスを操作する参照が自身のインスタンスになります。それを除けば、前掲スクリプト04-011と処理は大きく変わりません。細かい点をいくつか、メソッドごとに確かめます。

立方体の各面のをDisplayObjectインスタンスをCubeインスタンス内に配置するのが、以下のcreateFace()メソッドです(スクリプト第63〜75行目)。前掲スクリプト04-011の関数xCreateFace()の処理に加えて、立方体のCubeインスタンスの表示リストに面のDisplayObjectインスタンスを加える処理が含まれます(スクリプト第65行目)。

  1.     private function createFace(face:DisplayObject, nX:Number, nY:Number, nZ:Number, nRotationY:Number = 0, nRotationX:Number = 0):Sprite {
  2.       var faceSprite:Sprite = new Sprite();
  3.       addChild(faceSprite);
  4.       faceSprite.addChild(face);
  5.       faceSprite.x = nX;
  6.       faceSprite.y = nY;
  7.       faceSprite.z = nZ;
  8.       faceSprite.rotationY = nRotationY;
  9.       faceSprite.rotationX = nRotationX;
  10.       face.x = -unit;
  11.       face.y = -unit;
  12.       return faceSprite;
  13.     }

メソッドrotate()は、前掲スクリプト04-011のxRotate()がリスナー関数だったのに対して、メインタイムラインのスクリプトSPL-004のリスナー関数xRotate()から呼出されるかたちになりました(スクリプト第28〜36行目)。メソッドのふたつの引数には、y軸およびx軸回りの角度をそれぞれ受取ります。また、インスタンスの位置が予め決まりませんので、スクリプト第29〜30行目でxy座標をつねに確かめています。

  1.     public function rotate(nRotationY:Number, nRotationX:Number):void {
  2.       var nX:Number = x;
  3.       var nY:Number = y;
  4.       myMatrix3D.appendTranslation(-nX, -nY, 0);
  5.       myMatrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
  6.       myMatrix3D.appendRotation(nRotationX, Vector3D.X_AXIS);
  7.       myMatrix3D.appendTranslation(nX, nY, 0);
  8.       setOrder();
  9.     }

メソッドsetOrder()(スクリプト第37〜52行目)の実質的な処理は、前掲スクリプト04-011の関数xSetOrder()と同じです。以上から定義されたクラスが、つぎのスクリプトSPL-005のクラスCubeです。

スクリプトSPL-005■立方体をつくって表示するクラスCube
    // ActionScript 3.0クラス定義ファイル: Cube.as
    // 立方体のインスタンスを生成・表示する
  1. package {
  2.   import flash.display.DisplayObject;
  3.   import flash.display.Sprite;
  4.   import flash.geom.Matrix3D;
  5.   import flash.geom.Vector3D;
  6.   import flash.events.Event;
  7.   public class Cube extends Sprite {
  8.     private var unit:Number;
  9.     private var frontFace:Sprite;
  10.     private var backFace:Sprite;
  11.     private var leftFace:Sprite;
  12.     private var rightFace:Sprite;
  13.     private var topFace:Sprite;
  14.     private var bottomFace:Sprite;
  15.     private var myMatrix3D:Matrix3D;
  16.     public function Cube(front:DisplayObject, back:DisplayObject, left:DisplayObject, right:DisplayObject, top:DisplayObject, bottom:DisplayObject, edge:Number = 100) {
  17.       unit = edge / 2;
  18.       z = 0;
  19.       myMatrix3D = transform.matrix3D;
  20.       frontFace = createFace(front, 0, 0, -unit);
  21.       backFace = createFace(back, 0, 0, unit, 180, 0);
  22.       leftFace = createFace(left, -unit, 0, 0, 90, 0);
  23.       rightFace = createFace(right, unit, 0, 0, -90, 0);
  24.       topFace = createFace(top, 0, -unit, 0, 0, -90);
  25.       bottomFace = createFace(bottom, 0, unit, 0, 0, 90);
  26.       addEventListener(Event.ADDED, onAdded);
  27.     }
  28.     public function rotate(nRotationY:Number, nRotationX:Number):void {
  29.       var nX:Number = x;
  30.       var nY:Number = y;
  31.       myMatrix3D.appendTranslation(-nX, -nY, 0);
  32.       myMatrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
  33.       myMatrix3D.appendRotation(nRotationX, Vector3D.X_AXIS);
  34.       myMatrix3D.appendTranslation(nX, nY, 0);
  35.       setOrder();
  36.     }
  37.     private function setOrder():void {
  38.       var faces_array:Array = new Array();
  39.       var nChildren:uint = numChildren;
  40.       var i:uint;
  41.       var faceSprite:Sprite;
  42.       for (i = 0; i < nChildren; i++) {
  43.         faceSprite = getChildAt(i) as Sprite;
  44.         var myVector3D:Vector3D = faceSprite.transform.getRelativeMatrix3D(parent).position;
  45.         var nZ:Number = myVector3D.z;
  46.         if (nZ < 0) {
  47.           faceSprite.visible = true;
  48.           faces_array.push({face:faceSprite, z:nZ});
  49.         } else {
  50.           faceSprite.visible = false;
  51.         }
  52.       }
  53.       faces_array.sortOn("z", Array.NUMERIC | Array.DESCENDING);
  54.       var nStart:uint = nChildren - faces_array.length;
  55.       for (i = nStart; i < nChildren; i++) {
  56.         faceSprite = faces_array[i - nStart].face;
  57.         setChildIndex(faceSprite, i);
  58.       }
  59.     }
  60.     private function onAdded(eventObject:Event):void {
  61.       setOrder();
  62.     }
  63.     private function createFace(face:DisplayObject, nX:Number, nY:Number, nZ:Number, nRotationY:Number = 0, nRotationX:Number = 0):Sprite {
  64.       var faceSprite:Sprite = new Sprite();
  65.       addChild(faceSprite);
  66.       faceSprite.addChild(face);
  67.       faceSprite.x = nX;
  68.       faceSprite.y = nY;
  69.       faceSprite.z = nZ;
  70.       faceSprite.rotationY = nRotationY;
  71.       faceSprite.rotationX = nRotationX;
  72.       face.x = - unit;
  73.       face.y = - unit;
  74.       return faceSprite;
  75.     }
  76.   }
  77. }

ひとつつけ加えなければならないのは、スクリプトSPL-005第26行目でDisplayObject.addedイベント(定数Event.ADDED)にリスナーメソッドonAdded()を登録していることです。メソッドonAdded()は、setOrder()を呼出します(スクリプト第60〜63行目)。前掲スクリプト04-011では6面の重ね順を整える関数xSetOrder()の呼出しに当たります。

面の重ね順は、立方体のインスタンスが置かれた親タイムライン(DisplayObjectContainer)の座標空間における奥行き、つまりz座標値にもとづいて定めます。ところが、Cubeクラスのコンストラクタが呼出されたとき、まだインスタンスはどの親DisplayObjectContainerインスタンスの表示リストにも属していません。よって、親インスタンスにおける座標空間も調べようがないのです。具体的には、setOrder()メソッドのスクリプト第44行目でDisplayObject.parentプロパティの値がnullになってしまいます。

そのため、スクリプト第26行目はDisplayObject.addedイベントで、Cubeインスタンスが親DisplayObjectContainerオブジェクトに加えられるのを待ち、イベントリスナーonAdded()メソッドから面の重ね順を整えるsetOrder()メソッドを呼出しているのです。

このクラスCubeを前掲フレームアクション(スクプトSPL-004)で呼出せば、立方体のインスタンスがマウスポインタの位置に応じて回ります(前掲図04-028)。


タイムラインの操作をドキュメントクラスとして定義する
それでは、前掲フレームアクション(スクリプトSPL-004)を、ドキュメントクラスに設定するクラスMainとして定義します。それが以下のスクリプトSPL-006です。フレームアクションの関数xRotate()をメソッドrotate()としたほかは、ステートメントをただ単純にクラス定義に直しただけです。

スクリプトSPL-006■ドキュメントクラスに設定するクラスMain
    // ActionScript 3.0クラス定義ファイル: Main.as
    // ドキュメントクラスに設定
  1. package {
  2.   import flash.display.Sprite;
  3.   import flash.display.Bitmap;
  4.   import flash.events.Event;
  5.   public class Main extends Sprite {
  6.     private var nX:Number = stage.stageWidth / 2;
  7.     private var nY:Number = stage.stageHeight / 2;
  8.     private var nDeceleration:Number = 0.2;
  9.     private var mySprite:Cube;
  10.     public function Main() {
  11.       var frontBitmap:Bitmap = new Bitmap(new Image0(0, 0));
  12.       var backBitmap:Bitmap = new Bitmap(new Image1(0, 0));
  13.       var leftBitmap:Bitmap = new Bitmap(new Image3(0, 0));
  14.       var rightBitmap:Bitmap = new Bitmap(new Image2(0, 0));
  15.       var topBitmap:Bitmap = new Bitmap(new Image4(0, 0));
  16.       var bottomBitmap:Bitmap = new Bitmap(new Image5(0, 0));
  17.       mySprite =
          new Cube(frontBitmap, backBitmap, leftBitmap, rightBitmap, topBitmap, bottomBitmap);
  18.       addChild(mySprite);
  19.       mySprite.x = nX;
  20.       mySprite.y = nY;
  21.       addEventListener(Event.ENTER_FRAME, rotate);
  22.     }
  23.     private function rotate(eventObject:Event):void {
  24.       var nRotationY:Number = (mouseX - nX) * nDeceleration;
  25.       var nRotationX:Number = (mouseY - nY) * nDeceleration;
  26.       mySprite.rotate(nRotationY, nRotationX);
  27.     }
  28.   }
  29. }

これで、前掲スクリプト04-011は、ふたつのクラスとして定義することができました。ただ、折角クラスにしたのですから、もう少し機能をつけ加えることにしましょう。

クラスCubeへの機能の追加
手を加えるのは、スクリプトSPL-005のクラスCubeです。つぎの3つの機能をもたせます。

[1]面の数を6つ以内で減らせるようにします。なくす面は、コンストラクタメソッドCube()の引数にnullで指定します。

[2]立方体を6面で閉じないときは、裏側の面も表示しなければなりません。これは、裏面を非表示に(カリング)するメソッドsetOrder()で、面の数を確かめて処理することにします。

[3]前述のとおり、コンストラクタメソッドCube()の第7引数で、立方体のサイズを変えられるようにします。なお、面のDisplayObjectインスタンスは、基準点が左上角にあるものとします。

機能を追加したクラスCubeの定義は、後にスクリプトSPL-007として掲げます。まず、コンストラクタメソッドCube()が引数として受取る面のDisplayObjectインスタンスには、デフォルト値にnullを指定しました。

  1.     public function Cube(front:DisplayObject = null, back:DisplayObject = null, left:DisplayObject = null, right:DisplayObject = null, top:DisplayObject = null, bottom:DisplayObject = null, edge:Number = 100) {

これで、たとえば前面ひとつだけで、1辺が100ピクセルのCubeインスタンスは、つぎのように生成できることになります。

new Cube(frontBitmap)

この修正に伴って、つぎにメソッドcreateFace()にも手を加える必要があります。コンストラクタCube()の面の引数にnullが渡されたとき、createFace()メソッドで新たなSpriteをつくるのは無駄です。また、メソッドの中で面のDisplayObjectインスタンスに座標を設定しようとすればエラーになってしまいます。そこで、メソッドcreateFace()は、つぎのように修正します(スクリプト第68〜87行目)。

  1.     private var culling:Boolean = true;
  1.     private function createFace(face:DisplayObject, nX:Number, nY:Number, nZ:Number, nRotationY:Number = 0, nRotationX:Number = 0):Sprite {
  2.       var faceSprite:Sprite = null;
  3.       if (face) {
  4.         faceSprite = new Sprite();
  5.         addChild(faceSprite);
  6.         faceSprite.addChild(face);
  7.         faceSprite.x = nX;
  8.         faceSprite.y = nY;
  9.         faceSprite.z = nZ;
  10.         faceSprite.rotationY = nRotationY;
  11.         faceSprite.rotationX = nRotationX;
  12.         face.width = unit * 2;
  13.         face.height = unit * 2;
  14.         face.x = -unit;
  15.         face.y = -unit;
  16.       } else {
  17.         culling = false;
  18.       }
  19.       return faceSprite;
  20.     }

スクリプト第71行目で、戻り値となる変数(faceSprite)に初期値としてnullを設定しました。続く第72行目は、引数に渡された面のDisplayObjectインスタンスを調べ、nullであれば戻り値をnullのまま返します。

メソッドcreateFace()の第1引数に面としてnullが渡されれば、でき上がる立方体は6面が閉じないことになります。そこで、スクリプト第16行目にカリングするかどうかのBoolean型プロパティ(culling)を宣言し、初期値にはtrue(カリングする)を代入しています。そして、メソッドcreateFace()の第1引数がnullのとき、スクリプト第84行目でプロパティ値をfalseに書替えます。このプロパティ値を調べれば、カリングの要否がわかります。

また、スクリプト第79〜80行目は、引数に受取った面のDisplayObjectインスタンスの幅と高さを、コンストラクタCube()で指定された立方体の1辺の長さに定めています。

つぎに、メソッドsetOrder()は、以下のように修正します(スクリプト第38〜64行目)。スクリプト第47行目のifステートメントでカリング(変数culling)が要らない(false)のときは、面のSpriteインスタンス(変数faceSprite)の表示はとくに触らず、第48行目ですべての面を重ね順操作の対象として、面のインスタンスの配列(変数faces_array)に納めます。カリングが要る場合の処理(第50〜55行目)は、もとのCubeクラス(前掲スクリプトSPL-005)と変わりません。

  1.     private function setOrder():void {
  2.       var faces_array:Array = new Array();
  3.       var nChildren:uint = numChildren;
  4.       var i:uint;
  5.       var faceSprite:Sprite;
  6.       for (i = 0; i < nChildren; i++) {
  7.         faceSprite = getChildAt(i) as Sprite;
  8.         var myVector3D:Vector3D = faceSprite.transform.getRelativeMatrix3D(parent).position;
  9.         var nZ:Number = myVector3D.z;
  10.         if (! culling) {
  11.           faces_array.push({face:faceSprite, z:nZ});
  12.         } else {
  13.           if (nZ < 0) {
  14.             faceSprite.visible = true;
  15.             faces_array.push({face:faceSprite, z:nZ});
  16.           } else {
  17.             faceSprite.visible = false;
  18.           }
  19.         }
  20.       }
  1.     }

これで、クラスCubeに前述の機能が追加できました。クラス定義の全体は、つぎのスクリプトSPL-007のとおりです。

スクリプトSPL-007■立方体をつくって表示するクラスCubeに機能追加
    // ActionScript 3.0クラス定義ファイル: Cube.as
    // 立方体のインスタンスを生成・表示する
  1. package {
  2.   import flash.display.DisplayObject;
  3.   import flash.display.Sprite;
  4.   import flash.geom.Matrix3D;
  5.   import flash.geom.Vector3D;
  6.   import flash.events.Event;
  7.   public class Cube extends Sprite {
  8.     private var unit:Number;
  9.     private var frontFace:Sprite;
  10.     private var backFace:Sprite;
  11.     private var leftFace:Sprite;
  12.     private var rightFace:Sprite;
  13.     private var topFace:Sprite;
  14.     private var bottomFace:Sprite;
  15.     private var myMatrix3D:Matrix3D;
  16.     private var culling:Boolean = true;
  17.     public function Cube(front:DisplayObject = null, back:DisplayObject = null, left:DisplayObject = null, right:DisplayObject = null, top:DisplayObject = null, bottom:DisplayObject = null, edge:Number = 100) {
  18.       unit = edge / 2;
  19.       z = 0;
  20.       myMatrix3D = transform.matrix3D;
  21.       frontFace = createFace(front, 0, 0, -unit);
  22.       backFace = createFace(back, 0, 0, unit, 180, 0);
  23.       leftFace = createFace(left, -unit, 0, 0, 90, 0);
  24.       rightFace = createFace(right, unit, 0, 0, -90, 0);
  25.       topFace = createFace(top, 0, -unit, 0, 0, -90);
  26.       bottomFace = createFace(bottom, 0, unit, 0, 0, 90);
  27.       addEventListener(Event.ADDED, onAdded);
  28.     }
  29.     public function rotate(nRotationY:Number, nRotationX:Number):void {
  30.       var nX:Number = x;
  31.       var nY:Number = y;
  32.       myMatrix3D.appendTranslation(-nX, -nY, 0);
  33.       myMatrix3D.appendRotation(nRotationY, Vector3D.Y_AXIS);
  34.       myMatrix3D.appendRotation(nRotationX, Vector3D.X_AXIS);
  35.       myMatrix3D.appendTranslation(nX, nY, 0);
  36.       setOrder();
  37.     }
  38.     private function setOrder():void {
  39.       var faces_array:Array = new Array();
  40.       var nChildren:uint = numChildren;
  41.       var i:uint;
  42.       var faceSprite:Sprite;
  43.       for (i = 0; i < nChildren; i++) {
  44.         faceSprite = getChildAt(i) as Sprite;
  45.         var myVector3D:Vector3D = faceSprite.transform.getRelativeMatrix3D(parent).position;
  46.         var nZ:Number = myVector3D.z;
  47.         if (! culling) {
  48.           faces_array.push({face:faceSprite, z:nZ});
  49.         } else {
  50.           if (nZ < 0) {
  51.             faceSprite.visible = true;
  52.             faces_array.push({face:faceSprite, z:nZ});
  53.           } else {
  54.             faceSprite.visible = false;
  55.           }
  56.         }
  57.       }
  58.       faces_array.sortOn("z", Array.NUMERIC | Array.DESCENDING);
  59.       var nStart:uint = nChildren - faces_array.length;
  60.       for (i = nStart; i < nChildren; i++) {
  61.         faceSprite = faces_array[i - nStart].face;
  62.         setChildIndex(faceSprite, i);
  63.       }
  64.     }
  65.     private function onAdded(eventObject:Event):void {
  66.       setOrder();
  67.     }
  68.     private function createFace(face:DisplayObject, nX:Number, nY:Number, nZ:Number, nRotationY:Number = 0, nRotationX:Number = 0):Sprite {
  69.       var faceSprite:Sprite = null;
  70.       if (face) {
  71.         faceSprite = new Sprite();
  72.         addChild(faceSprite);
  73.         faceSprite.addChild(face);
  74.         faceSprite.x = nX;
  75.         faceSprite.y = nY;
  76.         faceSprite.z = nZ;
  77.         faceSprite.rotationY = nRotationY;
  78.         faceSprite.rotationX = nRotationX;
  79.         face.width = unit * 2;
  80.         face.height = unit * 2;
  81.         face.x = -unit;
  82.         face.y = -unit;
  83.       } else {
  84.         culling = false;
  85.       }
  86.       return faceSprite;
  87.     }
  88.   }
  89. }

コンストラクタメソッドCube()の引数に渡す面をnullにすると、その面をなくすことができます(図SPL-007左図)。その場合、裏返った面を非表示にするカリングは行われません(Tips SPL-003「カリングされているかどうかを確かめる」参照)。たとえば、つぎのように第6引数以降を省けば、底面なしで1辺が100ピクセルの立方体になります。

new Cube(frontBitmap, backBitmap, leftBitmap, rightBitmap, topBitmap)   // 底面の指定なし

コンストラクタCube()の第7引数は、立方体の1辺の長さをピクセル数で定めます(図SPL-007左図)。たとえば、つぎのステートメントは、1辺が100ピクセル立方体のインスタンスをつくります。

new Cube(frontBitmap, backBitmap, leftBitmap, rightBitmap, topBitmap, bottomBitmap, 50)
図SPL-007■立方体の面を減らしたり1辺の長さが変えられる
 
コンストラクタCube()の引数に渡す面をnullにすると、その面がなくなる(左図)。また、第7引数で立方体の1辺の長さが変えられる(右図)。

Tips SPL-003■カリングされているかどうかを確かめる
立方体の6面が閉じていないとき、カリングされていないことは、立方体を回してみればわかります。けれど、6面が閉じていると、裏側の面が表示されていないかどうかは、目では確かめられません。

その場合、つぎのようにメソッドsetOrder()の最後の行(第64行目)の手前で、面が納められた配列(変数faces_array)の長さをtrace()すればよいでしょう(図SPL-008上図)。カリングされていれば、重ね順を変えるべき面の数として、3より大きな数字は[出力]されないはずだからです(図SPL-008下図)。

  1.     private function setOrder():void {
  2.       var faces_array:Array = new Array();
            trace(faces_array.length);   // 確認用
  1.     }
図SPL-008■重ね順を変える面の配列の長さによりカリングが確かめられる

面を納めた配列(変数faces_array)の長さは、カリングが行われれば、3より大きくはならない。

Maniac! SPL-001■面の配列の最初の長さは1になる
Tips SPL-003の前掲図SPL-008下図のように、メソッドsetOrder()が最初に呼出されたとき、面の配列(変数faces_array)の長さが1になります。これは、立方体が真正面を向いており、上下左右の面は親インスタンスの座標空間においてz座標値がちょうど0になるため、表示する必要がないからです(前掲スクリプトSPL-007第50行目)。


[Prev/Next]


作成者: 野中文雄
作成日: 2010年4月20日


Copyright © 2001-2009 Fumio Nonaka.  All rights reserved.