サイトトップ

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

Adobe Flash非公式テクニカルノート

[ライブラリ]のビットマップを3次元空間で水平に回す

ID: FN1106001 Product: Flash CS5 and above Platform: All Version: 10 and above/ActionScript 3.0

[ライブラリ]に入れたビットマップをタイムラインに置いて、3次元空間の垂直軸つまりy軸で水平に回してみます。同じ表現でも、使うクラスによって組立ては違います。また、3次元空間における扱いも変わってきます。本稿では、3つの異なる手法をご紹介します。

[ライブラリ]のビットマップには、インスタンスが動的につくれるように、[クラス]としてImageという名前を設定しておきましょう(図001)。[ビットマッププロパティ]ダイアログボックスは、[ライブラリ]パネルのメニューから[プロパティ]で開きます。

図001■[ビットマッププロパティ]ダイアログボックスで[クラス]を設定する


01 BitmapをSpriteインスタンスの入れ子にしてDisplayObject.rotationYプロパティで回す
ビットマップは[基本クラス]としてBitmapDataを継承します(前掲図001参照)。BitmapDataはDisplayObjectのサブクラスではありませんので、そのままではタイムラインに置けません。そこで、ビットマップのインスタンスはBitmapクラスのコンストラクタに渡し、ビットマップが含まれたBitmapインスタンスをタイムラインに子として加えます。

BitmapはDisplayObjectクラスを継承しますので、DisplayObject.rotationYプロパティにより3次元空間で回すこともできます。ただし、注意しなければならないのは、基準点がビットマップイメージの左上角になることです(図002左図)。今回のお題では、真ん中を軸にして水平に回したいと思います。ところが、そのままインスタンスをDisplayObject.rotationYプロパティで回せば、ビットマップイメージの左端が中心軸になってしまいます。

そこでよく使われる手が、BitmapをSpriteインスタンスの入れ子にすることです。すると、Spriteインスタンスの基準点をビットマップイメージの中心に置けます(図002右図)。あとは、SpriteインスタンスをDisplayObject.rotationYプロパティで回せばよいのです。

図002■ビットマップが含まれたBitmapをSpriteインスタンスの入れ子にする

入れ子

ビットマップ(クラスImage)のイメージが含まれたBitmapオブジェクトをSpriteインスタンスに入れ子にしたのが、以下のスクリプト001です[*1]。Spriteインスタンスは、マウスポインタの水平位置に応じた向きと速さで水平に回ります(図003)。

図003■[ライブラリ]のビットマップがマウスポインタの水平位置に応じた向きと速さで水平に回る

スクリプト001■ビットマップが含まれたBitmapをSpriteインスタンスに入れ子にしてDisplayObject.rotationYプロパティで回す
    // フレームアクション: メインタイムライン
  1. var nCenterX:Number = stage.stageWidth / 2;
  2. var nCenterY:Number = stage.stageHeight / 2;
  3. var myInstance:Sprite = new Sprite();
  4. var myImage:BitmapData = new Image();
  5. var myBitmap:Bitmap = new Bitmap(myImage);
  6. addChild(myInstance);
  7. myInstance.addChild(myBitmap);
  8. myInstance.x = nCenterX;
  9. myInstance.y = nCenterY;
  10. myBitmap.x = -myImage.width / 2;
  11. myBitmap.y = -myImage.height / 2;
  12. myInstance.addEventListener(Event.ENTER_FRAME, xRotate);
  13. function xRotate(eventObject:Event):void {
  14.   var nRotation:Number = (stage.mouseX - nCenterX) * 0.2;
  15.   myInstance.rotationY += nRotation;
  16. }

スクリプト001第4〜7行目は、[ライブラリ]のビットマップ(クラスImage)のインスタンス(myImage)が含まれたBitmapオブジェクト(myBitmap)を、Spriteインスタンス(myInstance)に入れ子にしてステージに配置しています。

スクリプト001第8〜11行目で、Spriteインスタンス(myInstance)はステージ中央に置いたうえで、ビットマップイメージの中心にSpriteインスタンスの基準点がくるようBitmapインスタンス(myBitmap)の位置を動かしています。これでSpriteインスタンスをイメージの中心で回せます。

そして、スクリプト001第12行目以降は、インスタンスのDisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)にリスナー関数(xRotate())を加えて(第12行目)、マウスポインタの水平位置に応じた向きと速さでインスタンスを水平に回します(第13〜16行目)。

[*1] このスクリプトの処理内容について詳しくは、gihyo.jp連載「ActionScript 3.0で始めるオブジェクト指向スクリプティング」第34回「3次元空間における回転」をお読みください。


02 ビットマップで塗ったShapeインスタンスをDisplayObject.rotationYプロパティで回す
前項と同じお題を、少し違った角度で考えてみましょう。ビットマップが含まれたインスタンスをタイムラインに置くのでなく、空のインスタンスをビットマップで塗るのです。

インスタンスのもつGraphicsオブジェクトにビットマップ(BitmapDataオブジェクト)を塗るのが、Graphics.beginBitmapFill()メソッドです。第1引数には塗りのイメージとなるBitmapDataオブジェクトを渡します。オプションの第2引数はMatrixオブジェクトで、塗りのイメージを変形します。

Graphicsオブジェクト.beginBitmapFill(BitmapDataオブジェクト, 変換Matrixオブジェクト)

Graphics.beginBitmapFill()メソッドで塗ることができるインスタンスには、まずSpriteがあります。けれど、ただビットマップを塗って3次元空間で回すだけなら、もっと軽いShapeインスタンスで足ります。そこで、Shapeインスタンスにビットマップと同じ大きさの矩形を描き、ビットマップのイメージで塗ることにします。インスタンスがもつGraphicsオブジェクトは、Shape.graphicsプロパティから参照を得ます。

Graphicsオブジェクトに対してGraphics.beginBitmapFill()メソッドを呼出すとき、第1引数のビットマップインスタンスのみ渡すと、ビットマップのイメージは基準点を左上角としてタイル状に塗られます。インスタンスの真ん中を軸に回すためには、矩形は基準点が中心になるように描かなければなりません。すると、ビットマップが4つに分かれたように塗られてしまいます(図004)。

図004■Graphics.beginBitmapFill()メソッドの塗りはデフォルトでは基準点を左上角とする

Graphics.beginBitmapFill()メソッドの第2引数にMatrixオブジェクトを渡せば、塗り位置は動かせます。Matrixクラスで座標を動かすメソッドはMatrix.translate()です[*2]。引数には移動するxy座標値をピクセル単位で定めます。

Matrixオブジェクト.translate(x座標, y座標)

以下のスクリプト002は、Shapeインスタンスの基準点を中心にビットマップと同じ大きさの矩形を描き、ビットマップで塗りました。そのShapeインスタンスを、前掲スクリプト001と同じように、マウスポインタの水平位置に応じた向きと速さで水平に回します。動きの見た目は、前掲スクリプト001とまったく変わりません(前掲図003)。

スクリプト002■ビットマップで塗ったShapeインスタンスの矩形をDisplayObject.rotationYプロパティで回す
    // フレームアクション: メインタイムライン
  1. var nCenterX:Number = stage.stageWidth / 2;
  2. var nCenterY:Number = stage.stageHeight / 2;
  3. var myInstance:Shape = new Shape();
  4. var myGraphics:Graphics = myInstance.graphics;
  5. var myImage:BitmapData = new Image();
  6. var nWidth:Number = myImage.width;
  7. var nHeight:Number = myImage.height;
  8. var myMatrix:Matrix = new Matrix();
  9. var nX:Number = -nWidth / 2;
  10. var nY:Number = -nHeight / 2;
  11. addChild(myInstance);
  12. myInstance.x = nCenterX;
  13. myInstance.y = nCenterY;
  14. myMatrix.translate(nX, nY);
  15. myGraphics.beginBitmapFill(myImage, myMatrix);
  16. myGraphics.drawRect(nX, nY, nWidth, nHeight);
  17. myGraphics.endFill();
  18. myInstance.addEventListener(Event.ENTER_FRAME, xRotate);
  19. function xRotate(eventObject:Event):void {
  20.   var nRotation:Number = (stage.mouseX - nCenterX) * 0.2;
  21.   myInstance.rotationY += nRotation;
  22. }

スクリプト002第3〜4行目でShapeインスタンスからGraphicsオブジェクトの参照(Shape.graphicsプロパティ)を得て、第15〜17行目がビットマップ(クラスImage)と同じ大きさの矩形にビットマップイメージを塗っています。

スクリプト002第8行目はMatrixインスタンスをつくり、第14行目でMatrix.translate()メソッドによりビットマップイメージの中心が基準点になるよう座標を動かしています。そして、第15行目に、そのMatrixオブジェクトをGraphics.beginBitmapFill()メソッドの第2引数に渡しました。

スクリプト002のShapeインスタンスをつくってステージ中央に置く処理(第1〜3行目および第11〜13行目)は、インスタンスがShapeであること以外前掲スクリプト001と変わりません。また、インスタンスを3次元空間で水平に回すリスナー関数(第18〜22行目)は、スクリプト001とまったく同じです。

[*2] Matrixクラスについて、詳しくはAdobeデベロッパーセンター「Matrixクラス − 変換行列」をお読みください。


03 Bitmapインスタンスをビットマップイメージの中心で回す − Matrix3Dクラスを使う
ビットマップが含まれたBitmapインスタンスを、タイムラインに直置きしてビットマップイメージの中心で回せないでしょうか。Matrix3Dクラスを使えば、基準点以外を原点にしてインスタンスが回せます。このやり方で、お題のムービーをつくってみましょう。

Matrix3Dクラスは、3次元座標空間における(平行)移動や回転、伸縮という3つの変換を定めます。これらの変換は、座標空間の原点(0, 0, 0)をもとに行われます。インスタンスに変換を加える場合、この原点は親インスタンス(タイムライン)の基準点になります。したがって、Matrix3Dクラスの座標変換をうまく組合わせれば、インスタンスの基準点以外を原点にすることができるのです。

今回のお題では、Bitmapインスタンスを一旦移動して、親タイムラインの基準点とビットマップイメージの中心を重ねます。その後インスタンスを回せば、親タイムラインの基準点つまりビットマップの中心が軸になります。そのうえで、改めてインスタンスをもとの位置に戻せばよいのです。

インスタンスのもつMatrix3Dオブジェクトは、DisplayObject.transformプロパティからTransformオブジェクトが得られるので、そのTransform.matrix3Dプロパティで参照します。そして、(平行)移動はMatrix3D.appendTranslation()、回転にはMatrix3D.appendRotation()メソッドを用います[*3]

Matrix3Dオブジェクト.appendTranslation(x座標, y座標, z座標)
Matrix3Dオブジェクト.appendRotation(回転角, 回転軸)

Matrix3D.appendTranslation()メソッドに渡す3つの数値は、移動するxyzの各座標値です。Matrix3D.appendRotation()メソッドの第1引数は、回転角を度数で定めます。第2引数の回転軸はxyz軸がVector3Dクラスの定数で、それぞれVector3D.X_AXIS/Vector3D.Y_AXIS/Vector3D.Z_AXISとして備わっています。前者の座標も後者の角度も、ともにインスタンスの現在値に加算される値であることにご注意ください。

ビットマップが含まれたBitmapインスタンスをタイムラインに直置きして、Matrix3Dクラスによりビットマップイメージの中心で回したのがつぎのスクリプト003です。

スクリプト003■BitmapインスタンスをMatrix3Dクラスによりビットマップの中心で水平に回す
  1. var nCenterX:Number = stage.stageWidth / 2;
  2. var nCenterY:Number = stage.stageHeight / 2;
  3. var myImage:BitmapData = new Image();
  4. var myInstance:Bitmap = new Bitmap(myImage);
  5. var myMatrix3D:Matrix3D = new Matrix3D();
  6. myInstance.transform.matrix3D = myMatrix3D;
  7. addChild(myInstance);
  8. myInstance.x = nCenterX - myImage.width / 2;
  9. myInstance.y = nCenterY - myImage.height / 2;
  10. myInstance.addEventListener(Event.ENTER_FRAME, xRotate);
  11. function xRotate(eventObject:Event):void {
  12.   var nRotation:Number = (stage.mouseX - nCenterX) * 0.2;
  13.   myMatrix3D.appendTranslation(-nCenterX, -nCenterY, 0);
  14.   myMatrix3D.appendRotation(nRotation, Vector3D.Y_AXIS);
  15.   myMatrix3D.appendTranslation(nCenterX, nCenterY, 0);
  16. }

スクリプト003第5〜6行目が、BitmapインスタンスのDisplayObject.transformプロパティから得たTransform.matrix3Dプロパティに新たなMatrix3Dオブジェクトを設定しています。

インスタンスを回転するリスナー関数(xRotate())は、このMatrix3Dオブジェクトにビットマップイメージの中心で水平回転を加えます(スクリプト003第11〜16行目)。第13行目で3次元座標空間の原点にビットマップイメージの中心がくるよう、Matrix3D.appendTranslation()メソッドで移動させます。そのうえで、第14行目が原点を中心にした水平回転をMatrix3D.appendRotation()メソッドにより加えます。その後、改めてMatrix3D.appendTranslation()メソッドを呼出し、もとの位置に戻しています。結果として、この変換Matrix3DオブジェクトをもつBitmapインスタンスが、イメージの中心で水平に回ることになるのです。

[*3] Matrix3Dクラスの扱いについて詳しくは、gihyo.jp連載「ActionScript 3.0で始めるオブジェクト指向スクリプティング」第35回「Matrix3Dクラスによる座標変換」以降、およびAdobeデベロッパーセンター「Matrix3Dクラス − 変換行列2」をお読みください。



作成者: 野中文雄
作成日: 2011年6月18日


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