he 'rotation' property of a DisplayObject rotates the object about its registration point. Very often you would rather rotate an object about a point inside the object different than the registration point or about an external point. The simplest way to accomplish that task is by using the MatrixTransformer class in the fl.motion package. In this How-To we show how to do it. Click on the image below to open an example in a new window.
Download
Download the well-commented source file corresponding to the example above, rotation.fla.
* rotation.fla
Comments and Code
The class MatrixTransformer does make rotating about an arbitrary point very easy provided you use the static methods MatrixTransformer.rotateAroundInternalPoint and MatrixTransformer.rotateAroundExternalPoint in the way demonstrated below or in any other way that avoids using the current yourObject.transform.matrix at each rotation. The latter will cause an error to accumulate and eventually your object will shift significantly. The accumulating error is especially pronounced with MatrixTransformer.rotateAroundInternalPoint. The solution: Keep track of the current angle of rotation at each iteration rather than of the current yourObject.transform.matrix. Below is the code behind our example.
We begin by importing the MatrixTransformer class.
import fl.motion.MatrixTransformer;
We create two Shapes corresponding to the blue and the purple square. We add them as children of the MainTimeline and position them on the Stage.
var blue:Shape=new Shape();
this.addChild(blue);
blue.x=140;
blue.y=200;
var purple:Shape=new Shape();
this.addChild(purple);
purple.x=500;
purple.y=190;
The variables curPurpleAng and curBlueAng will store the current value of the rotation angle for each square.
var curPurpleAng:Number=0;
var curBlueAng:Number=0;
We set centers of rotation for each square. You can experiment by changing the points' coordinates. With our choice the center for the blue square falls within the square, the center for the purple square outside the purple square.
var blueRotCenter:Point=new Point(30,30);
var purpleRotCenter:Point=new Point(450,220);
We are calling the function that draws both squares as well as the dots representing the centers of rotation, and crosses representing the registration points.
drawShapes();
The next two lines are very important. We store the initial transform.matrix for each square in two variables purpleMat and blueMat. These two matrices will remain the same throughout the script and the animation. Every time we rotate the squares, we will use blueMat and purpleMat and the current values of the angles of rotation for each square to calculate the current transform.matrix objects for each square.
var purpleMat:Matrix=purple.transform.matrix.clone();
var blueMat:Matrix=blue.transform.matrix.clone();
The function rotateBlue rotates the blue square by the angle 'deg' (in degrees) from the INITIAL position of the blue square, similarly for rotatePurple. This is important to avoid errors. See comments below and at the end of the script.
function rotateBlue(deg:Number):void {
var mat:Matrix= blueMat.clone();
MatrixTransformer.rotateAroundInternalPoint(mat,blueRotCenter.x,
blueRotCenter.y,deg);
blue.transform.matrix=mat;
}
function rotatePurple(deg:Number):void {
var mat:Matrix= purpleMat.clone();
MatrixTransformer.rotateAroundExternalPoint(mat,purpleRotCenter.x,
purpleRotCenter.y,deg);
purple.transform.matrix=mat;
}
The function rotateBlue uses the static method of the MatrixTransformer class
MatrixTransformer.rotateAroundInternalPoint
that adds rotation to the matrix passed as the first parameter.
The function rotatePurple uses the static method of the MatrixTransformer class
MatrixTransformer.rotateAroundExternalPoint
that adds rotation to the matrix passed as the first parameter.
The difference between the two methods lies in the interpretation of the coordinates x and y passed to the methods as the second and the third parameter. For rotateAroundInternalPoint, the coordinates are interpreted as relative to the registration point of the object. For rotateAroundExternalPoint, the coordinates are interpreted as relative to the Stage. The last parameter in both methods is the angle of rotation, in degrees.
On ENTER_FRAME, the current rotation angle for each squre is increased (or decreased) by 2 degrees and the functions that rotate squares are applied. Note we are keeping track of the current angles and not of the current transfrom matrices.
this.addEventListener(Event.ENTER_FRAME,onEnter);
function onEnter(e:Event):void {
curPurpleAng=(curPurpleAng+2)%360;
rotatePurple(curPurpleAng);
curBlueAng=(curBlueAng-2)%360;
rotateBlue(curBlueAng);
}
Finally, the function that draws all shapes. We skip below this easy part of the code. Please see the fla file.
function drawShapes():void {
..........
..........
}
Important comment:
Should 'deg' in rotatePurple and rotateBlue, say rotateBlue, represent the INCREMENT of the angle of rotation at each step, we would have to use the current value of blue.transform.matrix and the code would look as follows:
var mat:Matrix = blue.transform.matrix.clone();
MatrixTransformer.rotateAroundInternalPoint(mat,blueRotCenter.x,
blueRotCenter.y,deg);
blue.transform.matrix = mat;
This would lead to a building up error that would gradually move the rotating object from its proper position. This error is more pronounced in rotateAroundInternalPoint method than in rotateAroundExternalPoint method. So if you have to dynamically retrieve the value of transform.matrix of your object, use rotateAroundExternalPoint. In that case, you have to translate the coordinates of the center of rotation to their equivalents with respect to the Stage.
/////////////////////////////
import fl.motion.MatrixTransformer;
/*
We create two Shapes corresponding to the blue and the purple square.
We add them as children of the MainTimeline and position them on the Stage.
*/
var blue:Shape=new Shape();
this.addChild(blue);
blue.x=140;
blue.y=200;
var purple:Shape=new Shape();
this.addChild(purple);
purple.x=500;
purple.y=190;
/*
The variables curPurpleAng and curBlueAng will store the current value of
the rotation angle for each square.
*/
var curPurpleAng:Number=0;
var curBlueAng:Number=0;
/*
We set centers of rotation for each square. You can experiment by changing
the points' coordinates. With our choice the center for the blue square falls within the square,
the center for the purple square outside the purple square.
*/
var blueRotCenter:Point=new Point(30,30);
var purpleRotCenter:Point=new Point(450,220);
/*
We are calling the function that draws both squares as well as the dots representing
the centers of rotation, and crosses representing the registration points.
*/
drawShapes();
/*
The next two lines are very important. We store the initial transform.matrix for
each square in two variables purpleMat and blueMat. These two matrices will remain
the same throughout the script and the animation. Every time we rotate the squares,
we will use blueMat and purpleMat and the current values of the angles of rotation
for each square to calculate the current transform.matrix objects for each square.
*/
var purpleMat:Matrix=purple.transform.matrix.clone();
var blueMat:Matrix=blue.transform.matrix.clone();
/*
The function rotateBlue rotates the blue square by the angle 'deg' (in degrees)
from the INITIAL position of the blue square, similarly for rotatePurple.
This is important to avoid errors. See comment at the end of the script.
The function rotateBlue uses the static method of the MatrixTransformer class
MatrixTransformer.rotateAroundInternalPoint
that adds rotation to the matrix passed as the first parameter.
The function rotatePurple uses the static method of the MatrixTransformer class
MatrixTransformer.rotateAroundExternalPoint
that adds rotation to the matrix passed as the first parameter.
The difference between the two methods lies in the interpretation of the
coordinates x and y passed to the methods as the second and the third parameter.
For rotateAroundInternalPoint, the coordinates are interpreted as relative to the
registration point of the object. For rotateAroundExternalPoint, the coordinates are
interpreted as relative to the Stage.
*/
function rotateBlue(deg:Number):void {
var mat:Matrix= blueMat.clone();
MatrixTransformer.rotateAroundInternalPoint(mat,blueRotCenter.x,blueRotCenter.y,deg);
blue.transform.matrix=mat;
}
function rotatePurple(deg:Number):void {
var mat:Matrix= purpleMat.clone();
MatrixTransformer.rotateAroundExternalPoint(mat,purpleRotCenter.x,purpleRotCenter.y,deg);
purple.transform.matrix=mat;
}
/*
On ENTER_FRAME, the current rotation angle for each squre is increased (or decreased) by
2 degrees and the functions that rotate squares are applied. Note we are keeping track of
the current angles and not of the current transfrom matrices.
*/
this.addEventListener(Event.ENTER_FRAME,onEnter);
function onEnter(e:Event):void {
curPurpleAng=(curPurpleAng+2)%360;
rotatePurple(curPurpleAng);
curBlueAng=(curBlueAng-2)%360;
rotateBlue(curBlueAng);
}
//The function that draws all shapes.
function drawShapes():void {
blue.graphics.lineStyle();
blue.graphics.beginFill(0x000066);
blue.graphics.drawRect(-60,-60,120,120);
blue.graphics.endFill();
//------------------
blue.graphics.beginFill(0xCC0000);
blue.graphics.drawCircle(blueRotCenter.x,blueRotCenter.y,3);
blue.graphics.endFill();
//--------------
blue.graphics.lineStyle(2,0xFFFF00);
blue.graphics.moveTo(-5,0);
blue.graphics.lineTo(5,0);
blue.graphics.moveTo(0,-5);
blue.graphics.lineTo(0,5);
//--------
purple.graphics.lineStyle();
purple.graphics.beginFill(0x660066);
purple.graphics.drawRect(0,0,60,60);
purple.graphics.endFill();
//-----------
purple.graphics.lineStyle(2,0xFFFF00);
purple.graphics.moveTo(-5,0);
purple.graphics.lineTo(5,0);
purple.graphics.moveTo(0,-5);
purple.graphics.lineTo(0,5);
//----------
this.graphics.lineStyle();
this.graphics.beginFill(0xCC0000);
this.graphics.drawCircle(purpleRotCenter.x,purpleRotCenter.y,3);
this.graphics.endFill();
}
/*
Comment:
Should 'deg' in rotatePurple and rotateBlue, say rotateBlue, represent the INCREMENT
of the angle of rotation at each step, we would have to use the current value
of blue.transform.matrix and the code would look as follows:
var mat:Matrix= blue.transform.matrix.clone();
MatrixTransformer.rotateAroundInternalPoint(mat,blueRotCenter.x,blueRotCenter.y,deg);
blue.transform.matrix=mat;
This would lead to a building up error that would gradually move the rotating object
from its proper position. This error is more pronounced in rotateAroundInternal
method than in rotateAroundExternal method. So if you have to dynamically
retrieve the value of transform.matrix of your object, use rotateAroundExternal.
In that case, you have to translate the coordinates of the center of rotation to their
equivalents with respect to the Stage.
*/
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment