AS3: Main - The ultimate tutorial reading experience
If anyone saw my last tutorial on rotating around points, this is a much cleaner and faster way to achieve the same effect, now that I actually vaguely know how to use matrices.
I'm working in two dimensions here, but this theory can also be applied to three.
You don't need to know anything about matrices for this tutorial - just take my word for things.
What is a matrix?
A matrix is essentially a rectangular set of data which can be manipulated in various ways. In my feeble attempt to represent them with text alone, they look something like this:
[ 0 5 6 ]
[ 7 4 2 ]
[ 3 4 5 ] // This is supposed to be a single matrix. This one doesn't mean anything - it's just an example.
A brief introduction
Since I'm not going to go through an entire tutorial on further maths here, here are three facts which you should understand if you want to make sense of what follows:
1. An object's position can be expressed by a single matrix:
[ x ]
[ y ] // This is a much more meaningful matrix for our purposes.
If you want, you can also consider that the above example is equal to:
x [ 1 ]
[ 0 ]
+
y [ 0 ]
[ 1 ]
2. A transformation can also be expressed by a matrix.
For example, the following represents a reflection in the x axis:
[ 1 0 ]
[ 0 -1 ]
And a rotation anti-clockwise by n radians is:
[ cos(n) -sin(n) ]
[ sin(n) cos(n) ]
3. Multiplying matrices together is weird.
For a start, the order in which the matrices are placed matters - (A * B) = (B * A) when A and B are numbers, but not for radians.
I don't really want to get into this right now, but to multiply:
[ a b ][ x ]
[ c d ][ y ]
You go along the columns of the first value and rows of the second, multiplying each pair together and adding on, so the result of the above would be:
[ (ax + by) ]
[ (cx + dy) ]
Since we're on the subject of transformations, the last matrix represents the new values of x and y after being transformed by the matrix with a, b, c and d.
A rotational transformation around the origin
As we've already established, the matrix:
[ cos(n) -sin(n) ]
[ sin(n) cos(n) ]
gives us a rotation anti-clockwise by n. This is true of the sort of graphs you may draw in school, with axis pointing in sensible directions. Since Flash features an inverted y axis, though, anti-clockwise equals clockwise, which is convenient for us.
So, let's hurry things along. To rotate an object n radians clockwise, we use:
[ cos(n) -sin(n) ][ x ]
[ sin(n) cos(n) ][ y ]
=
[ x(cos(n)) - y(sin(n)) ]
[ x(sin(n)) + y(cos(n)) ]
=
[ new x ]
[ new y ]
To put that into code:
import flash.events.MouseEvent;
stage.addEventListener(MouseEvent.CLICK, onClick);
function rotateClockwise(vc:DisplayObject, va:Number):void{
var ma:Number = (va * Math.PI) / 180; // convert an angle from degrees to radians
var myx:Number = vc.x; // we hold onto the x value since it changes before we're through with it
vc.x = (Math.cos(ma) * vc.x) - (Math.sin(ma) * vc.y);
vc.y = (Math.sin(ma) * myx) + (Math.cos(ma) * vc.y) ;
}
function onClick(ev:MouseEvent){
rotateClockwise(mr_rotaty, 10);
}
Try the above code by naming an object 'mr_rotaty'. It should rotate 10 degrees around the top-left corner every time you click.
So far so good
...but what good is just rotating around the origin all the time? We need to add in a couple of options so you can get rotation around any object you choose.
Well, the clip's co-ordinates are relative to the origin, so all we really need to do is subtract the co-ordinates of whatever we want to rotate around before the transformation, then add them back on at the end:
import flash.events.MouseEvent;
stage.addEventListener(MouseEvent.CLICK, onClick);
function rotateClockwise(vc:DisplayObject, va:Number, vx:Number = 0, vy:Number = 0):void{
var ma:Number = (va * Math.PI) / 180;
var dx:Number = vc.x - vx; // the difference between the clip's x and y
var dy:Number = vc.y - vy; // values and what you want to rotate around
vc.x = (Math.cos(ma) * dx) - (Math.sin(ma) * dy) + vx; // pretty much the same, except this time we add the
vc.y = (Math.sin(ma) * dx) + (Math.cos(ma) * dy) + vy; // difference back on to get us back to the right co-ordinate space
}
function onClick(ev:MouseEvent){
rotateClockwise(mr_rotaty, 10, mouseX, mouseY);
}
Try that code in the same circumstances as the last one - your clip should now rotate 10 degrees around your mouse every time you click.
And to sing us out...
If you want the actual graphics to rotate around your point as well (I didn't add that into the main tutorial this time since it seemed fairly specific) is pretty straightforward. Just add this line:
vc.rotation += va;
I won't insult your intelligence by telling you where it goes.
One last thing
Flash, and indeed everything, has accuracy problems when it comes small, long or irrational numbers (such as, say, sine or cosine of most things). This shouldn't be a problem for general rotation, but if you're trying to make anything which needs to stay realistic, such as, for example, something that's going to be running for extended lengths of time, it's probably a good idea to store the object's original x and y as variables and base your rotations off of those rather than their values after the last change.
That's about it for this.
Thanks to
dELtaluca - http://deltaluca.newgrounds.com/ - for introducing me to matrices in the first place
Gust - http://gusttheasguy.newgrounds.com/ - for constantly reminding my of how crappy and inaccurate Flash is
So long
Tutorial by
- Eddy Larkin
- Paranoia