绕某点旋转学习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 }