基準点以外で拡大・回転

2009.12.23 水曜日

自分が昔ハマったことのあるプログラムですが、Flashではシンボル化されたオブジェクトの基準点を中心に、回転やスケール変更を行います。オブジェクト(ステージ上)の任意の点を中心に拡大したい場合には、プログラムに少しコツが必要です。

下記の参考スクリプトの2つの関数、RotateA()とRotateB()は、結果は同じになりますが、アプローチが少し違います。どちらの関数も引数は「操作したいオブジェクト、基準点の座標、相対回転角度」になっています。

RotateA()が、いつも自分で使っている方法。まず、回転させる直前と直後に指定したオブジェクトの親視点で基準点の位置を取得。この差分だけ回転した直後にオブジェクトを移動し位置を補正します。

RotateB()はオブジェクトの基準点自体を移動させる方法。最近読んだ_level0.KAYAC 「getBounds + Matrixで、もう基準点にはこだわらない。」を参考にしました。Matrixを使っているあたり、こっちの方がプロっぽいです。cellfusion blog 「DisplayObject.transform.matrix」でもほぼ同じ方法を紹介しています。

この2つの方法以外にも、オブジェクトを入れ子にして操作する方法がありますが、あまりスマートではないので省略します。

package {
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	public class Main extends MovieClip {

		//オブジェクト
		private var Sample_mc:MovieClip;
		private var Point_mc:MovieClip;

		//動作タイプ
		private var check:Boolean;

		public function Main():void {

			//オブジェクト(グレーの四角)を描画
			Sample_mc = new MovieClip();
			this.addChild(Sample_mc);
			Sample_mc.x = 200;
			Sample_mc.y = 150;
			var g:Graphics = Sample_mc.graphics;
			g.beginFill(0x999999, 1);
			g.drawRect(-10, -10, 200, 150);

			//基準点を描画
			Point_mc = new MovieClip();
			this.addChild(Point_mc);

			//初期値
			check = true;

			//リスナー登録
			this.addEventListener(Event.ENTER_FRAME, Update);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, Change);
		}

		//動作タイプを変更
		private function Change(e:Event):void {

			//更新
			check = !check;
		}

		//表示更新
		private function Update(e:Event):void {

			//回転
			if (check) RotateA(Sample_mc, new Point(200, 200), 1);
			else RotateB(Sample_mc, new Point(300, 150), -2);
		}

		//回転
		private function RotateA(_object:MovieClip, _p:Point, _rotation:Number):void {

			//基準点を描画
			Draw(_p);

			//基準点をステージ上の座標で設定
			var p:Point = _object.globalToLocal(_p);

			//変更前の座標を取得
			var a:Point = _object.localToGlobal(p);

			//回転
			_object.rotation += _rotation;

			//変更後の座標を取得
			var b:Point = _object.localToGlobal(p);

			//差を補正
			var c:Point = a.subtract(b);
			_object.x += c.x;
			_object.y += c.y;
		}

		//回転
		private function RotateB(_object:MovieClip, _p:Point, _rotation:Number):void {

			//基準点を描画
			Draw(_p);

			//現状のマトリクスを取得
			var mx:Matrix = _object.transform.matrix;

			//オブジェクトの領域を取得
			var r:Rectangle = _object.getBounds(_object.parent);

			//基準点を任意の座標に変更
			mx.translate(-_p.x, -_p.y);

			//回転
			mx.rotate(_rotation / 180 * Math.PI);

			//基準点を初期位置に戻す
			mx.translate(_p.x, _p.y);

			//反映
			_object.transform.matrix = mx;
		}

		//基準点を描画
		private function Draw(_p:Point):void {

			//赤点を描画
			var g:Graphics = Point_mc.graphics;
			g.clear();
			g.beginFill(0xFF0000, 1);
			g.drawCircle(_p.x, _p.y, 5);
		}
	}
}

Posted by tmdf|

trackback

http://tmdf.net/blog/20091223_base_poin.html/trackback

comments(0)

POST NEW COMMENT

  • name:*
  • e-mail:*

    The content of this field is kept private and will not be shown publicly.
  • website:
  • comment:*

    Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code>
    Lines and paragraphs break automatically.

Photo

PROFILE

森田 考陽 [Takaaki Morita]
Twitter: @tmdf
Other: mtdf.net

Designer / Programmer

RECENT POSTS

MONTHLY ARCHIVES