绕某点旋转学习Matrix的使用,以及MatrixTransformer.rotateAroundExternalPoint方法
圆点可以移动位置,长方形鼠标拖动,先看MatrixTransformer.rotateAroundExternalPoint的使用
import fl.motion.MatrixTransformer;
//-----------------初始化全局变量------------
var m:Matrix;//rotateAroundExternalPoint方法的初始矩阵,在点击时初始化
var tempY:Number = point.y;//旋转初始起点,以后是上一次终点
var tempX:Number = point.x;//
//-----------------旋转中心点的移动控制-------------------
point.addEventListener(MouseEvent.MOUSE_DOWN,downmove);
function downmove(e:MouseEvent) {
e.target.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP,up);
}
//-------------------当鼠标按在线上时------------------
line.addEventListener(MouseEvent.MOUSE_DOWN,down);
function down(e:MouseEvent) {
tempY = mouseY;//得到旋转起始点
tempX = mouseX;//
m = line.transform.matrix;//实例化旋转矩阵,不能放在旋转函数中,否则有偏移
stage.addEventListener(MouseEvent.MOUSE_MOVE,moving_fun);//鼠标移动侦听
stage.addEventListener(MouseEvent.MOUSE_UP,up);//鼠标松开侦听
}
//-------------------------当鼠标松开时--------------------------
function up(e:MouseEvent) {
point.stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_MOVE,moving_fun);
}
//--------------------------鼠标移动时旋转控制-------------------------------
function moving_fun(e:Event ):void {
//下面的new_A、old_A实际上是规范刻度,逆时针刻度由0~360,顺时针刻度由0~-360,防止由-180移到180产生
//360的增加值,所以需要判断,由转换后的刻度差再累加,来实现连续的绝对值增加的角度
var new_A:Number = Math.atan2(mouseY - point.y,mouseX - point.x)* 180 / Math.PI;//;
var old_A:Number = Math.atan2(tempY - point.y,tempX - point.x)* 180 / Math.PI;// ;
if (new_A * old_A < 0 && mouseX - point.x < 0) {//判断是否跨过180(-180)线,0度线不需判断
if (new_A > old_A) {//由负角到正角
old_A = Math.min(new_A,old_A) + 360;//把正刻度变负
} else {//由正角到负角
new_A = Math.min(new_A,old_A) + 360;//把负刻度变正
}
}
//把 (new_A-old_A)+ 累加,可以得到从x轴开始的逆时针刻度由0~360,顺时针刻度由0~-360的变化值
//MatrixTransformer.rotateAroundInternalPoint(m,e.currentTarget.mouseX,e.currentTarget.mouseY,1);
MatrixTransformer.rotateAroundExternalPoint(m,point.x,point.y,new_A-old_A);//
line.transform.matrix = m;
tempY = mouseY;//下一次的起点
tempX = mouseX;
}
//-----------------初始化全局变量------------
var m:Matrix;//rotateAroundExternalPoint方法的初始矩阵,在点击时初始化
var tempY:Number = point.y;//旋转初始起点,以后是上一次终点
var tempX:Number = point.x;//
//-----------------旋转中心点的移动控制-------------------
point.addEventListener(MouseEvent.MOUSE_DOWN,downmove);
function downmove(e:MouseEvent) {
e.target.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP,up);
}
//-------------------当鼠标按在线上时------------------
line.addEventListener(MouseEvent.MOUSE_DOWN,down);
function down(e:MouseEvent) {
tempY = mouseY;//得到旋转起始点
tempX = mouseX;//
m = line.transform.matrix;//实例化旋转矩阵,不能放在旋转函数中,否则有偏移
stage.addEventListener(MouseEvent.MOUSE_MOVE,moving_fun);//鼠标移动侦听
stage.addEventListener(MouseEvent.MOUSE_UP,up);//鼠标松开侦听
}
//-------------------------当鼠标松开时--------------------------
function up(e:MouseEvent) {
point.stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_MOVE,moving_fun);
}
//--------------------------鼠标移动时旋转控制-------------------------------
function moving_fun(e:Event ):void {
//下面的new_A、old_A实际上是规范刻度,逆时针刻度由0~360,顺时针刻度由0~-360,防止由-180移到180产生
//360的增加值,所以需要判断,由转换后的刻度差再累加,来实现连续的绝对值增加的角度
var new_A:Number = Math.atan2(mouseY - point.y,mouseX - point.x)* 180 / Math.PI;//;
var old_A:Number = Math.atan2(tempY - point.y,tempX - point.x)* 180 / Math.PI;// ;
if (new_A * old_A < 0 && mouseX - point.x < 0) {//判断是否跨过180(-180)线,0度线不需判断
if (new_A > old_A) {//由负角到正角
old_A = Math.min(new_A,old_A) + 360;//把正刻度变负
} else {//由正角到负角
new_A = Math.min(new_A,old_A) + 360;//把负刻度变正
}
}
//把 (new_A-old_A)+ 累加,可以得到从x轴开始的逆时针刻度由0~360,顺时针刻度由0~-360的变化值
//MatrixTransformer.rotateAroundInternalPoint(m,e.currentTarget.mouseX,e.currentTarget.mouseY,1);
MatrixTransformer.rotateAroundExternalPoint(m,point.x,point.y,new_A-old_A);//
line.transform.matrix = m;
tempY = mouseY;//下一次的起点
tempX = mouseX;
}
再看使用Matrix的使用
import fl.motion.MatrixTransformer;
//-----------------初始化全局变量------------
var m:Matrix;//rotateAroundExternalPoint方法的初始矩阵,在点击时初始化
var tempY:Number = point.y;//旋转初始起点,以后是上一次终点
var tempX:Number = point.x;//
//-----------------旋转中心点的移动控制-------------------
point.addEventListener(MouseEvent.MOUSE_DOWN,downmove);
function downmove(e:MouseEvent) {
e.target.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP,up);
}
//-------------------当鼠标按在线上时------------------
line.addEventListener(MouseEvent.MOUSE_DOWN,down);
function down(e:MouseEvent) {
tempY = mouseY;//得到旋转起始点
tempX = mouseX;//
m = line.transform.matrix.clone();//实例化旋转矩阵,不能放在旋转函数中,否则有偏移
stage.addEventListener(MouseEvent.MOUSE_MOVE,moving_fun);//鼠标移动侦听
stage.addEventListener(MouseEvent.MOUSE_UP,up);//鼠标松开侦听
}
//-------------------------当鼠标松开时--------------------------
function up(e:MouseEvent) {
point.stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_MOVE,moving_fun);
}
//--------------------------鼠标移动时旋转控制-------------------------------
function moving_fun(e:Event ):void {
//下面的new_A、old_A实际上是规范刻度,逆时针刻度由0~360,顺时针刻度由0~-360,防止由-180移到180产生
//360的增加值,所以需要判断,由转换后的刻度差再累加,来实现连续的绝对值增加的角度
var new_A:Number = Math.atan2(mouseY - point.y,mouseX - point.x) * 180 / Math.PI;//这里需要角度的大小比较
var old_A:Number = Math.atan2(tempY - point.y,tempX - point.x) * 180 / Math.PI;//不能换成弧度
if (new_A * old_A < 0 && mouseX - point.x < 0) {//判断是否跨过180(-180)线,0度线不需判断
if (new_A > old_A) {//由负角到正角
old_A = Math.min(new_A,old_A) + 360;//把正刻度变负
} else {//由正角到负角
new_A = Math.min(new_A,old_A) + 360;//把负刻度变正
}
}
//把 (new_A-old_A)+ 累加,可以得到从x轴开始的逆时针刻度由0~360,顺时针刻度由0~-360的变化值
m.translate(-point.x,-point.y);
m.rotate((new_A-old_A)* Math.PI /180) ;
//上面的new_A、old_A是基于角度的计算和判断,所以弧度要到这里才能转换
m.translate(point.x,point.y);
line.transform.matrix = m;
tempY = mouseY;//下一次的起点
tempX = mouseX;
}
//-----------------初始化全局变量------------
var m:Matrix;//rotateAroundExternalPoint方法的初始矩阵,在点击时初始化
var tempY:Number = point.y;//旋转初始起点,以后是上一次终点
var tempX:Number = point.x;//
//-----------------旋转中心点的移动控制-------------------
point.addEventListener(MouseEvent.MOUSE_DOWN,downmove);
function downmove(e:MouseEvent) {
e.target.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP,up);
}
//-------------------当鼠标按在线上时------------------
line.addEventListener(MouseEvent.MOUSE_DOWN,down);
function down(e:MouseEvent) {
tempY = mouseY;//得到旋转起始点
tempX = mouseX;//
m = line.transform.matrix.clone();//实例化旋转矩阵,不能放在旋转函数中,否则有偏移
stage.addEventListener(MouseEvent.MOUSE_MOVE,moving_fun);//鼠标移动侦听
stage.addEventListener(MouseEvent.MOUSE_UP,up);//鼠标松开侦听
}
//-------------------------当鼠标松开时--------------------------
function up(e:MouseEvent) {
point.stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_MOVE,moving_fun);
}
//--------------------------鼠标移动时旋转控制-------------------------------
function moving_fun(e:Event ):void {
//下面的new_A、old_A实际上是规范刻度,逆时针刻度由0~360,顺时针刻度由0~-360,防止由-180移到180产生
//360的增加值,所以需要判断,由转换后的刻度差再累加,来实现连续的绝对值增加的角度
var new_A:Number = Math.atan2(mouseY - point.y,mouseX - point.x) * 180 / Math.PI;//这里需要角度的大小比较
var old_A:Number = Math.atan2(tempY - point.y,tempX - point.x) * 180 / Math.PI;//不能换成弧度
if (new_A * old_A < 0 && mouseX - point.x < 0) {//判断是否跨过180(-180)线,0度线不需判断
if (new_A > old_A) {//由负角到正角
old_A = Math.min(new_A,old_A) + 360;//把正刻度变负
} else {//由正角到负角
new_A = Math.min(new_A,old_A) + 360;//把负刻度变正
}
}
//把 (new_A-old_A)+ 累加,可以得到从x轴开始的逆时针刻度由0~360,顺时针刻度由0~-360的变化值
m.translate(-point.x,-point.y);
m.rotate((new_A-old_A)* Math.PI /180) ;
//上面的new_A、old_A是基于角度的计算和判断,所以弧度要到这里才能转换
m.translate(point.x,point.y);
line.transform.matrix = m;
tempY = mouseY;//下一次的起点
tempX = mouseX;
}
还有一个小实例
源码如下:
/*在flash cs3中(cs4适用),当主时间轴(stage)上有影片剪辑的实例,且该影片剪辑有实例名称,
并且关闭了“自动声明舞台上的实例”功能时(文件->发布设置->flash->ActionScript 3.0设置),
你需要在文档类中声明类为dynamic,或者打开“自动声明舞台上的实例”
*/
package {
//作者Joel,修改了时间长后漂移旋转中心的现象
import fl.motion.MatrixTransformer;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
public class rotateAroundPoint extends Sprite {//dynamic
private var xshift:Number;//x方向偏移旋转中心的位移
private var yshift:Number;//y方向偏移旋转中心的位移
private var isMoving:Boolean;
private var rotation_mc:MovieClip;//选定的旋转目标
private var matrix:Matrix;//旋转目标的矩阵
private var obj:Object;//存储鼠标的位置
private var angularVel:Number;//矩阵旋转的角度
private var decay:Number;//衰减率
public function rotateAroundPoint() {
init();
}
private function init():void {
addEventListener(MouseEvent.MOUSE_DOWN,pressed);
stage.addEventListener(MouseEvent.MOUSE_UP,released);
stage.addEventListener(Event.ENTER_FRAME,run);
isMoving = false;
decay = .99;
xshift = 0;
yshift = 0;
}
private function pressed(e:Event):void {
isMoving = true;
rotation_mc = MovieClip(e.target);
angularVel = 0;
xshift = mouseX - rotation_mc.x;
yshift = mouseY - rotation_mc.y;
matrix = rotation_mc.transform.matrix;
obj = {x:mouseX,y:mouseY};
}
private function released(e:Event):void {
isMoving = false;
}
private function run(e:Event):void {
if (isMoving) {
//当鼠标移动时更新旋转对象的位置,鼠标不动时不影响
rotation_mc.x = mouseX - xshift;
rotation_mc.y = mouseY - yshift;
//计算旋转的角度
angularVel = angularVel * decay;
var A:Number = 0.75;//最大振幅
var angle:Number = Math.atan2(rotation_mc.y - mouseY,rotation_mc.x - mouseX);//返回-π~+π
angularVel += A * Math.cos(angle);
//如果鼠标不移动,旋转对象就不需要从本身读取矩阵
obj.x!=mouseX||obj.y!=mouseY?matrix=rotation_mc.transform.matrix:NaN;
MatrixTransformer.rotateAroundExternalPoint(matrix,mouseX,mouseY,angularVel);
rotation_mc.transform.matrix=matrix;
//应用矩阵旋转对象时,更新x、y方向的位移
xshift=mouseX-rotation_mc.x;
yshift=mouseY-rotation_mc.y;
//便于鼠标移动时记录下位置
obj={x:mouseX,y:mouseY};
}
}
}
}
并且关闭了“自动声明舞台上的实例”功能时(文件->发布设置->flash->ActionScript 3.0设置),
你需要在文档类中声明类为dynamic,或者打开“自动声明舞台上的实例”
*/
package {
//作者Joel,修改了时间长后漂移旋转中心的现象
import fl.motion.MatrixTransformer;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
public class rotateAroundPoint extends Sprite {//dynamic
private var xshift:Number;//x方向偏移旋转中心的位移
private var yshift:Number;//y方向偏移旋转中心的位移
private var isMoving:Boolean;
private var rotation_mc:MovieClip;//选定的旋转目标
private var matrix:Matrix;//旋转目标的矩阵
private var obj:Object;//存储鼠标的位置
private var angularVel:Number;//矩阵旋转的角度
private var decay:Number;//衰减率
public function rotateAroundPoint() {
init();
}
private function init():void {
addEventListener(MouseEvent.MOUSE_DOWN,pressed);
stage.addEventListener(MouseEvent.MOUSE_UP,released);
stage.addEventListener(Event.ENTER_FRAME,run);
isMoving = false;
decay = .99;
xshift = 0;
yshift = 0;
}
private function pressed(e:Event):void {
isMoving = true;
rotation_mc = MovieClip(e.target);
angularVel = 0;
xshift = mouseX - rotation_mc.x;
yshift = mouseY - rotation_mc.y;
matrix = rotation_mc.transform.matrix;
obj = {x:mouseX,y:mouseY};
}
private function released(e:Event):void {
isMoving = false;
}
private function run(e:Event):void {
if (isMoving) {
//当鼠标移动时更新旋转对象的位置,鼠标不动时不影响
rotation_mc.x = mouseX - xshift;
rotation_mc.y = mouseY - yshift;
//计算旋转的角度
angularVel = angularVel * decay;
var A:Number = 0.75;//最大振幅
var angle:Number = Math.atan2(rotation_mc.y - mouseY,rotation_mc.x - mouseX);//返回-π~+π
angularVel += A * Math.cos(angle);
//如果鼠标不移动,旋转对象就不需要从本身读取矩阵
obj.x!=mouseX||obj.y!=mouseY?matrix=rotation_mc.transform.matrix:NaN;
MatrixTransformer.rotateAroundExternalPoint(matrix,mouseX,mouseY,angularVel);
rotation_mc.transform.matrix=matrix;
//应用矩阵旋转对象时,更新x、y方向的位移
xshift=mouseX-rotation_mc.x;
yshift=mouseY-rotation_mc.y;
//便于鼠标移动时记录下位置
obj={x:mouseX,y:mouseY};
}
}
}
}
1 import flash.display.MovieClip; 2 import flash.geom.Matrix; 3 import flash.geom.Point; 4 import flash.events.MouseEvent; 5 import flash.events.Event; 6 7 var isLoop:Boolean = false; 8 //防止误差累计,在循环外获取一次matrix 9 var m:Matrix = mc.transform.matrix; 10 //x、y是mc本地坐标空间的数值 11 function rotate( x:Number, y:Number, angleDegrees:Number):void 12 { 13 var point:Point = new Point(x,y); 14 //把 point转换到 m 的坐标空间 15 point = m.transformPoint(point); 16 //把 m 的坐标空间换成本地坐标空间 17 m.tx -= point.x; 18 m.ty -= point.y; 19 //把 m 的坐标空间换成本地坐标空间 20 m.rotate(angleDegrees*(Math.PI/180)); 21 //把 m 的坐标空间又换回父坐标空间; 22 m.tx += point.x; 23 m.ty += point.y; 24 25 mc.transform.matrix = m; 26 27 } 28 29 this.addEventListener(Event.ENTER_FRAME,init); 30 function init(e:Event):void 31 { 32 if(mc.rotation>=90) 33 { 34 mc.rotation=90; 35 this.removeEventListener(Event.ENTER_FRAME,init); 36 cl(null) 37 return;; 38 } 39 rotate(0,0,1); 40 } 41 stage.addEventListener(MouseEvent.CLICK,cl); 42 function cl(e:Event):void 43 { 44 isLoop = ! isLoop; 45 if (isLoop) 46 { 47 this.addEventListener(Event.ENTER_FRAME,loop); 48 } 49 else 50 { 51 if (this.hasEventListener(Event.ENTER_FRAME)) 52 { 53 this.removeEventListener(Event.ENTER_FRAME,loop); 54 } 55 } 56 } 57 function loop(e:Event):void 58 { 59 rotate(100,50,5); 60 }