AS3 CS4の中でレイアウトしたものを回す

2009/04/19

こんにちは。きんくまです。

サンプルファイルを一通り見てみました。
→3 次元(3D)での操作

なんとなく概要だけつかめた感じです。昨日のdrawTriangleの部分とかも、カリング・uvtの例が載っていてわかりやすかったです。

さて、今回の件です。
実際の案件では、私はASで1からプログラムするのではなく、Flashを使って中でオーサリングしていきながら、プログラムを書くスタイルが多いです。なので、その場合どうやって3Dをやっていくのか試してみました。

まず、失敗談から。
ルート直下においたMCをツールの「3D回転ツール」「3D変換ツール」を使って変形すると、パブリッシュ時になぜか、原点に移動してしまい各変形が無効になってしまいました。ルート直下ではなく、入れ子にしたMCの場合は大丈夫です。これはなんでなのかさっぱりわかりません。ちなみに、ドキュメントクラスを設定しない場合はこうなりませんでした。

で、とにかく今回できたやつをお見せしておきます。

これはルート直下においたwrapperというMC内に4枚のMCを手動でおいて、オーサリング上でxyzの値を設定してレイアウトしたものです。

コードのことを説明したいので、作成した2枚を。
ドキュメントクラス

package
{
  import flash.display.MovieClip;
  import flash.display.Sprite;
  import flash.display.StageAlign;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.geom.Matrix3D;
  import flash.geom.Point;
  import flash.geom.Vector3D;

  public class Sample1 extends Sprite
  {
    public var wrapper:MovieClip;
    public var deg:Number = 0;
    public var sz:SortZ;
    public var panels:Array;

    public function Sample1()
    {
      this.stage.addEventListener(Event.ENTER_FRAME, ef);
      sz = new SortZ(wrapper);
      panels = new Array();
      var i:int; var len:int = wrapper.numChildren;
      for (i = 0; i < len; i++) {
        panels.push(wrapper.getChildAt(i));
      }
    }

    private function ef(e:Event):void
    {
      deg += 1;
      wrapper.rotationY = deg;
      sz.update();

      //消失点を設定
      var mX:Number = this.stage.mouseX;
      var mY:Number = this.stage.mouseY;
      this.root.transform.perspectiveProjection.projectionCenter = new Point(mX, mY);
    }

  }

}

Zsortを実現するクラスです。 Zsort.as

package
{
  import flash.display.DisplayObjectContainer;

  public class SortZ
  {
    private var container:DisplayObjectContainer;
    private var obj3ds:Array;

    public function SortZ(container:DisplayObjectContainer)
    {
      this.container = container;
      resetContainer();
    }

    public function setContainer(container:DisplayObjectContainer):void
    {
      this.container = container;
      resetContainer();
    }

    private function resetContainer():void
    {
      obj3ds = new Array();
      var i:int;
      var len:int = container.numChildren;
      var obj:Object3D;
      for (i = 0; i < len; i++) {
        obj = new Object3D(container.getChildAt(i));
        obj3ds[i] = obj;
      }
    }

    public function update():void
    {
      var i:int;
      var len:int = obj3ds.length;
      var obj:Object3D;
      for (i = 0; i < len; i++) {
        obj = obj3ds[i];
        obj.updateZ();
      }
      obj3ds.sortOn("z", Array.DESCENDING | Array.NUMERIC);
      for (i = 0; i < len; i++) {
        container.setChildIndex(obj3ds[i].obj, i);
      }
    }
  }

}
import flash.display.DisplayObject;
import flash.geom.Matrix3D;

class Object3D {
  public var z:Number;
  public var obj:DisplayObject;

  public function Object3D(obj:DisplayObject) {
    this.obj = obj;
  }

  public function updateZ():void
  {
    var mt3:Matrix3D = obj.transform.getRelativeMatrix3D(obj.root);
    z = mt3.position.z;
  }
}

——————
ここから解説
——————
Zsort.asなんですが一番大事なところは

obj3ds.sortOn("z", Array.DESCENDING | Array.NUMERIC);

の部分です。これは、前回も書いた本にも載っていたんですが、adobeのヘルプにも載っていました。
Matrix3D オブジェクトを使用した表示の並べ替え

Array.sortOn関数はArrayの中にobjectを入れてあげて、そのobjectのプロパティでArrayを並び替えることができるものです。objectのz値がわかりさえすれば並び替えることができるんですが、ひとつ問題があります。
wrapperの中にある各パネルのz値は、wrapperのrotationYを変化させて回しているだけだと変化がないんです。

これを解決するには、コードの

obj.transform.getRelativeMatrix3D(obj.root);

という部分でやります。これは、ある座標を基準にした見かけ上のx,y,z座標を測定するものみたいです。

あと、前回わからないといっていたperspectiveProjectionなんですが、これって消失点を設定するものみたいです。
なので、今回はマウスの置いてある位置を消失点に設定するようにしてみました。

オーサリングの参考になればと思い、flaファイルを含めたやつをアップしました。

それから、今回WebDesigning誌の「Flash Lab._3Dを利用したループアニメーションとUI」を参考にしました。ありがとうございました。
Web Designing 2009年5月号

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る