*Photo by broma.*

Who hasn’t been confused by the way Flash handles angles before?

Flash deals with angles in two different ways: degrees (from -180 to +180 for rotations), which are intuitive to designers, and radians (for the trigonometric functions like `Math.sin()`

and `Math.cos()`

), which are intuitive to mathematicians. The result is that developers find themselves trying to cope with different ways of using angles, which *isn’t* intuitive at all!

I’ve written a couple of classes to help with this. If you already understand the problems and just want to fix them, grab them in a zip file here or from snipplr here. They should be easy enough to make sense of.

If you’d like to read more about what the classes do, understand why we express angles in different ways, and find out just what the heck a radian is, anyway, then read on…

### Degrees are like slices of cake

When we’re first taught about angles, the teacher usually uses the example of a giant cake cut into 360 even slices, each representing one degree. This analogy is both easy to grasp and delicious to contemplate.

360 is a great number to use for this, because it can be divided in so many different ways: halves, thirds, quarters, fifths, sixths, eighths… Apparently this is a happy coincidence: the ancient Sumerians and Babylons loved the number 60, and 360 is roughly the number of days in a year, so it seemed like a good choice. Sure, that’s an oversimplification at best and total hearsay at worst, but who cares?

Degrees in the range 0-360 are very useful for measuring angles “in the real world”, partly because negative measurements are confusing and partly because they’re easy to mark on a protractor.

### Rotations are clockwise or anti-clockwise

All DisplayObjects have a public property called rotation. It’s used to rotate the object, unsurprisingly, and it uses degrees to do so. For example, you can set `displayObject.rotation = 90`

to rotate an object a quarter-turn clockwise from its starting point, or `displayObject.rotation = 270`

to rotate it three-quarters of a full turn clockwise.

What’s confusing is that the value it returns — the value you get if you call `trace( displayObject.rotation )`

— is in the range -180 to +180. Positive values indicate a rotation clockwise, while negative values indicate a rotation anti-clockwise. (As Keith Peters points out in Making Things Move, this is the opposite to the way things are normally done in maths and physics calculations.) A three-quarter-turn clockwise is the same as a quarter-turn anti-clockwise, so when you set `displayObject.rotation = 270`

, you’re actually setting `displayObject.rotation = -90`

.

This is actually a sensible way of doing things; it lets us think about rotations as being to the left or right of a base direction. I personally always get mixed up when trying to visualise angles in this range, though (often I mentally add 180 so that -180 to 180 becomes 0 to 360, but of course that’s not correct), so I wrote this function to convert angles from rotation-range to regular-range:

^{?}View Code ACTIONSCRIPT3

public function degFromRot( p_rotInput:Number ):Number { var degOutput:Number = p_rotInput; while ( degOutput >= 360 ) { degOutput -= 360; } while ( degOutput < 0 ) { degOutput += 360; } return degOutput; } |

Call `degFromRot( displayObject.rotation )`

and you’ll get a nice neat angle, in degrees, between 0 and 360. For completeness’s sake, I wrote another function to do the opposite:

^{?}View Code ACTIONSCRIPT3

public function rotFromDeg( p_degInput:Number ):Number { var rotOutput:Number = p_degInput; while ( rotOutput > 180 ) { rotOutput -= 360; } while ( rotOutput < -180 ) { rotOutput += 360; } return rotOutput; } |

You might have noticed that I’m using Hungarian notation in the above snippets. Wait! Don’t run away! It’s *good* Hungarian notation, the way it’s *supposed* to be used, as explained in this excellent article from Joel on Software. The basic idea is to prefix all your “rotation” variables (degrees in the range -180 to +180) with “rot” and all your “degree” variables (degrees in the range 0 to 360) with “deg”. I recommend doing this throughout your game; that way, it’s easy to keep track of what kind of unit a certain variable is using in your code.

This also makes it obvious when you’re using the wrong function. `rotAngle = rotFromDeg( degAngle )`

is correct because the two *rot*s are on the left and the two *deg*s are on the right; they match up. `rotAngle = degFromRot( degAngle )`

is clearly wrong, on the other hand.

### Radians have something to do with bread

I’m surprised by how many developers are using radians in their code without really knowing what they are. They’re actually not a difficult concept to grasp, but you have to think about them in the right way.

I’m going to assume here that you know about π (hereafter “pi”). Quick recap: it’s roughly equal to 3.14, and it’s useful when talking about circles, as the circumference of any circle is equal to pi times twice its radius, and the area of any circle is equal to pi times the square of its radius. For way more info than you need, check out Wikipedia’s article.

We’re told that ( 2 * pi ) radians is equal to 360 degrees. That’s true, but it doesn’t help understand what a radian is. Our natural idea would be to try to use the cake analogy again — but ( 2 * pi ) is roughly 6.28, and how do you split a cake into 6.28 pieces? I guess you could take a hundred cakes, and split them into 628 pieces, and that would be equivalent, but this doesn’t make matters any clearer.

We need a different analogy, and following with the food theme, I like to use breadcrumbs. Imagine you’re walking in a big circle that has a radius of about one mile, and that you’re leaving a trail of breadcrumbs behind you as you go, like in Hansel and Gretel. If you know the angle between your current point and your starting point, how can you work out how long your trail is?

First let’s think about how long the trail would be if you walked around the entire circle. Obviously, it must be as long as the circumference of the circle: ( 2 * pi ) * ( 1 mile ), or roughly 6.28 miles.

What about if you’d made it round half of the circle? Well, it’d be 0.5 * ( 2 * pi ) * ( 1 mile ), or roughly 3.14 miles.

Now, how about if you were just 73 degrees from your starting point? That implies that you’ve gone 73/360ths of the way around the circle. So, the length of the trail would be ( 73 / 360 ) * ( 2 * pi ) * ( 1 mile ), or roughly 1.27 miles.

We can rewrite this: 73 * ( 2 * pi / 360 ) * ( 1 mile ), which can be simplified to 73 * ( pi / 180 ) * ( 1 mile ). Aha, now 73 stands on its own, so this suggests a general formula we can use. If we’re *n* degrees from our starting point, then the length of the trail must be equal to n * ( pi / 180 ) * ( 1 mile ).

“Wouldn’t it be better if we could get rid of that pesky ( pi / 180 ) term, though? It’s kind of irritating to have to calculate it every single time.” Yes, it is, and that’s where radians come in. If we measure the angle in radians (we’ll use the letter *m* for this), then the length of the breadcrumb trail is just m * ( 1 mile ), or *m miles*.

And that’s all a radian is. **A radian is the unit of measurement for angles so that the length of an arc of a circle is equal to the radius of the circle multiplied by the angle, in radians, of the arc.** It’s a bit of a backwards definition, but that’s not unheard of. The metre, for example, is defined as the distance light will travel in a vacuum in one 299,792,458th of a second.

Now we need to link radians and degrees. That’s not hard. We’ve already seen that n * ( pi / 180 ) * ( 1 mile ) = m * ( 1 mile ), so with a bit of simple algebra we can show that m = n * ( pi / 180 ) and n = m * ( 180 / pi ). Therefore, **1 degree = ( pi / 180 ) radians, and 1 radian = ( 180 / pi ) degrees.**

Using this, I’ve written another couple of functions to convert between degrees and radians:

^{?}View Code ACTIONSCRIPT3

public static function degFromRad( p_radInput:Number ):Number { var degOutput:Number = ( 180 / Math.PI ) * p_radInput; return degOutput; } public static function radFromDeg( p_degInput:Number ):Number { var radOutput:Number = ( Math.PI / 180 ) * p_degInput; return radOutput; } |

As you can see, I’m using “rad” as the prefix for all variables measured in radians.

I’ve also got a couple of functions for converting between radians and rotations:

^{?}View Code ACTIONSCRIPT3

public static function rotFromRad( p_radInput:Number ):Number { return rotFromDeg( degFromRad( p_radInput ) ); } public static function radFromRot( p_rotInput:Number ):Number { return radFromDeg( degFromRot( p_rotInput ) ); } |

### Sweet 540 Nosebone to ( 3 * pi / 2 ) Indy

Thanks to games like Tony Hawk’s Pro Skater, gamers are all happy to use angles in degrees greater than 360. A thirteen-year-old automatically knows that turning 540 degrees in the air means you land the same way as if you’d turned 180 degrees. Trouble is, in code, if we try to work out the difference in angles (by tracing 540 – 180), we get 360, not zero. We know that these are the same thing, but computers don’t; we need to be able to keep our angles inside their “normal” ranges to be able to calculate differences like this. I’ve written three functions for this:

^{?}View Code ACTIONSCRIPT3

public static function degFromDeg( p_degInput:Number ):Number { var degOutput:Number = p_degInput; while ( degOutput >= 360 ) { degOutput -= 360; } while ( degOutput < 0 ) { degOutput += 360; } return degOutput; } public static function rotFromRot( p_rotInput:Number ):Number { var rotOutput:Number = p_rotInput; while ( rotOutput > 180 ) { rotOutput -= 360; } while ( rotOutput < -180 ) { rotOutput += 360; } return rotOutput; } public static function radFromRad( p_radInput:Number ):Number { var radOutput:Number = p_radInput; while ( radOutput >= 2 * Math.PI ) { radOutput -= 2 * Math.PI; } while ( radOutput < -( 2 * Math.PI ) ) { radOutput += 2 * Math.PI; } return radOutput; } |

The names of the functions are not ideal, but they are easy to remember. If you have any better suggestions, please let me know.
I’ve actually plugged these functions into the `radFromDeg()`

and `degFromRad()`

functions, which you can see in the final file below.

Radians are used in the trigonometric functions like Math.sin() and Math.cos() because they feel like a more “natural” unit in these cases. This is not immediately obvious if you don’t usually use such functions, but there’s a list of reasons this feels like the case here, if you’re interested. And, of course, radians are useful if you need to quickly measure how far you’ve walked along the edge of a circle.

### Optimisation

Optimisation is not my strong point. I used this excellent article to do a little optimisation, but I suspect this could all be made even more efficient. The final *Angle* class is here; click the little triangle to expand it:

^{?}View Code ACTIONSCRIPT3

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | package com.michaeljameswilliams.gamedev.angles { /** * Full details: http://gamedev.michaeljameswilliams.com/2009/04/24/angles-in-flash/ * Hungarian notation idea: http://www.joelonsoftware.com/articles/Wrong.html * Optimisation credit: http://www.nbilyk.com/optimizing-actionscript-3 * * Usage: import com.michaeljameswilliams.gamedev.angles.Angle * var degAngle:Number = Angle.degFromRad( radAngle ); * * @author MichaelJWilliams */ public class Angle { private const localPi:Number = Math.PI; private const localTwoPi:Number = Math.PI * 2; private const oneOver180:Number = 1 / 180; private const oneOverPi:Number = 1 / localPi; public function Angle() { trace( "The com.michaeljameswilliams.gamedev.angles.Angle class does not need to be instantiated" ); } /** * @param p_degInput Angle, in degrees * @return Angle, in degrees, in range 0 to 360 */ public static function degFromDeg( p_degInput:Number ):Number { var degOutput:Number = p_degInput; while ( degOutput >= 360 ) { degOutput -= 360; } while ( degOutput < 0 ) { degOutput += 360; } return degOutput; } /** * @param p_rotInput Angle, in degrees * @return Angle, in degrees, in range -180 to + 180 */ public static function rotFromRot( p_rotInput:Number ):Number { var rotOutput:Number = p_rotInput; while ( rotOutput > 180 ) { rotOutput -= 360; } while ( rotOutput < -180 ) { rotOutput += 360; } return rotOutput; } /** * @param p_radInput Angle, in radians * @return Angle, in radians, in range 0 to ( 2 * pi ) */ public static function radFromRad( p_radInput:Number ):Number { var radOutput:Number = p_radInput; while ( radOutput >= localTwoPi ) { radOutput -= localTwoPi; } while ( radOutput < -localTwoPi ) { radOutput += localTwoPi; } return radOutput; } /** * @param p_degInput Angle, in degrees * @return Angle, in degrees, in range -180 to +180 */ public static function rotFromDeg( p_degInput:Number ):Number { var rotOutput:Number = p_degInput; while ( rotOutput > 180 ) { rotOutput -= 360; } while ( rotOutput < -180 ) { rotOutput += 360; } return rotOutput; } /** * @param p_rotInput Angle, in degrees * @return Angle, in degrees, in range 0 to 360 */ public static function degFromRot( p_rotInput:Number ):Number { var degOutput:Number = p_rotInput; while ( degOutput >= 360 ) { degOutput -= 360; } while ( degOutput < 0 ) { degOutput += 360; } return degOutput; } /** * @param p_radInput Angle, in radians * @return Angle, in degrees, in range 0 to 360 */ public static function degFromRad( p_radInput:Number ):Number { var degOutput:Number = 180 * oneOverPi * radFromRad( p_radInput ); return degOutput; } /** * @param p_degInput Angle, in degrees * @return Angle, in radians, in range 0 to ( 2 * pi ) */ public static function radFromDeg( p_degInput:Number ):Number { var radOutput:Number = localPi * oneOver180 * degFromDeg( p_degInput ); return radOutput; } /** * @param p_radInput Angle, in radians * @return Angle, in degrees, in range -180 to +180 */ public static function rotFromRad( p_radInput:Number ):Number { return rotFromDeg( degFromRad( p_radInput ) ); } /** * @param p_rotInput Angle, in degrees * @return Angle, in radians, in range 0 to ( 2 * pi ) */ public static function radFromRot( p_rotInput:Number ):Number { return radFromDeg( degFromRot( p_rotInput ) ); } } } |

If you’ve never used static functions before, all you need to do is `import`

the class, then just call `Angle.function()`

— there’s no need to call `var angle:Angle = new Angle()`

.

A brief list of the optimisations I’ve done:

- Stored the mathematical constants as
`const`

s within the class - Multiplied by a fraction instead of dividing
- Stored these fractions as
`const`

s within the class

I also tested these functions against others, like ones using the modulo operator, and found that they worked the fastest. But if you know of any ways to speed them up, please let me know.

The above article also mentions that if a function needs to be run multiple times in quick succession — like in a loop — it will run faster if it’s a function of an instantiated class, rather than a static function. So, I’ve put together this companion class you can use for just that sort of situation:

^{?}View Code ACTIONSCRIPT3

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | package com.michaeljameswilliams.gamedev.angles { /** * Full details: http://gamedev.michaeljameswilliams.com/2009/04/24/angles-in-flash/ * Hungarian notation idea: http://www.joelonsoftware.com/articles/Wrong.html * Optimisation credit: http://www.nbilyk.com/optimizing-actionscript-3 * * Use this instead of the Angle functions when you need extra speed * and are going to use the functions multiple times (e.g. over a loop) * * Usage: import com.michaeljameswilliams.gamedev.angles.Angle * var angleUtil:AngleUtil = new AngleUtil(); * var degAngle:Number = angleUtil.degFromRad( radAngle ); * * @author MichaelJWilliams */ public class AngleUtil { private const localPi:Number = Math.PI; private const localTwoPi:Number = Math.PI * 2; private const oneOver180:Number = 1 / 180; private const oneOverPi:Number = 1 / localPi; public function AngleUtil() { } /** * @param p_degInput Angle, in degrees * @return Angle, in degrees, in range 0 to 360 */ public function degFromDeg( p_degInput:Number ):Number { var degOutput:Number = p_degInput; while ( degOutput >= 360 ) { degOutput -= 360; } while ( degOutput < 0 ) { degOutput += 360; } return degOutput; } /** * @param p_rotInput Angle, in degrees * @return Angle, in degrees, in range -180 to + 180 */ public function rotFromRot( p_rotInput:Number ):Number { var rotOutput:Number = p_rotInput; while ( rotOutput > 180 ) { rotOutput -= 360; } while ( rotOutput < -180 ) { rotOutput += 360; } return rotOutput; } /** * @param p_radInput Angle, in radians * @return Angle, in radians, in range 0 to ( 2 * pi ) */ public function radFromRad( p_radInput:Number ):Number { var radOutput:Number = p_radInput; while ( radOutput >= localTwoPi ) { radOutput -= localTwoPi; } while ( radOutput < -localTwoPi ) { radOutput += localTwoPi; } return radOutput; } /** * @param p_degInput Angle, in degrees * @return Angle, in degrees, in range -180 to +180 */ public function rotFromDeg( p_degInput:Number ):Number { var rotOutput:Number = p_degInput; while ( rotOutput > 180 ) { rotOutput -= 360; } while ( rotOutput < -180 ) { rotOutput += 360; } return rotOutput; } /** * @param p_rotInput Angle, in degrees * @return Angle, in degrees, in range 0 to 360 */ public function degFromRot( p_rotInput:Number ):Number { var degOutput:Number = p_rotInput; while ( degOutput >= 360 ) { degOutput -= 360; } while ( degOutput < 0 ) { degOutput += 360; } return degOutput; } /** * @param p_radInput Angle, in radians * @return Angle, in degrees, in range 0 to 360 */ public function degFromRad( p_radInput:Number ):Number { var degOutput:Number = 180 * oneOverPi * radFromRad( p_radInput ); return degOutput; } /** * @param p_degInput Angle, in degrees * @return Angle, in radians, in range 0 to ( 2 * pi ) */ public function radFromDeg( p_degInput:Number ):Number { var radOutput:Number = localPi * oneOver180 * degFromDeg( p_degInput ); return radOutput; } /** * @param p_radInput Angle, in radians * @return Angle, in degrees, in range -180 to +180 */ public function rotFromRad( p_radInput:Number ):Number { return rotFromDeg( degFromRad( p_radInput ) ); } /** * @param p_rotInput Angle, in degrees * @return Angle, in radians, in range 0 to ( 2 * pi ) */ public function radFromRot( p_rotInput:Number ):Number { return radFromDeg( degFromRot( p_rotInput ) ); } } } |

You can also download these classes in a zip file, or from my snipplr page.

I hope you find these useful One thing you could do immediately is rotate one object to face another (or the mouse) by using a function like this one to get the angle between the objects in radians, and using `displayObject1.rotation = rotFromRad( radAngle )`

to easily manage the actual rotation.

If you have any suggestions (or find any bugs), please let me know via the comments!

{ 16 comments… read them below or add one }

Thanks! This was really helpful.

You’re welcome, Anthony Glad you found it useful.

Hey, you redirected me here from your avoider game tutorial.

I’ve read it and while I understand what your doing… it didn’t help me (perhaps I don’t understand as well i as I would like)

This is the code, and it doesn’t work.

I have the guy drawn with his..uh.. dot going to the right.

I did what I thought was right, and when it didn’t I looked further for something explaining a bit better. I did end up finding one, but it was doing the same thing I was doing, but his worked and mine didn’t.

This is the post that I found: http://kirill-poletaev.blogspot.com/2010/07/rotate-object-to-mouse-using-as3.html

and my code is below

Oops!

I have a post here that shows what exactly IS wrong with the rotation

http://horizonshadow.org/adventures-in-flash-number-2/

Hey Josh,

Oooh, looks like you’re passing the

`rotX`

and`rotY`

arguments to Math.atan2() in the wrong order.There might be something else, but let me know if swapping those helps first

Erm. nope. Still nothing.

I’m sure it’s something incredibly stupid and easy to fix..

As a side note: If I wanted to put 2 text boxes on the playscreen and get them to display the radians var and the degrees var… I’d put a function in PlayScreen class and pass the vars from avatar into that function right?

If so… what’s the prefix for the textbox, as .text apparently doesn’t work for :numbers.

(I’m sure you explained it earlier, but i’ve been away from flash for the past week due to an excessive about of baseball games and work.

Oh, OK. Dang. What’s it look like now?

Yeah I think you could do it like that. You’ll have to convert the number to a string, like so:

(rather than

`theTextBox.text = myNumber;`

).It’s more or less the same thing. (not sure if it’s exactly the same or not, I was using the blog upload to compare but I changed some things since then.)

I understand what it’s doing, I don’t understand the conversion process. Just for giggles I drew something on paper, giving the mouse the location (200,0) and the avatar (0,200). You minus each from each, then when you find the Radian it spits out -1. If you times it by 180, then divide by pi, you get something like -57.

I’m probably wrong, seeing as school hasn’t started again yet and I’m braindead math wise atm, but shouldn’t the angle be 45 after doing that?

(I appologize if I sound like a complete moron, I haven’t done math in 3 months)

sorry, I meant -45, not 45…. which wouldn’t actually make sense if the mouse was up there.

I have tried multiplying by -1 in the program, it didn’t help any. Just reversed what it was doing normally. (obviously)

Are you remembering to use tan?

Erm….

I decided to put a TestAvatar on the screen to text until I got it working on a stationary object.

…I ran into a problem when adding the TestAvatar to the screen though. I put the addchild in the Avatar constructor, which worked fine. The coordinates were in the TestAvatar class.

Somehow, the TestAvatar has managed to rotate itself 45 degrees, and goes WAY off the screen for any coordinate other than 200,200 …

It worked once, and the avatar looked at the TestAvatar, then I changed the location of the TestAvatar and things exploded.

Don’t suppose this is a common issue..?

Oh my. I’ve learned something new about flash… giving a child to another child gives the second child the first childs stuff.

confusedHow might I add the TestAvatar to the screen without getting error 1009?

I’m back from holiday!

Still there, Josh? How are you adding the things to the screen at the moment?

Hey,

Just a quick blurb, i know this is an old post.

But wouldn’t using modulo be faster than that while loop your using?

The same would go for all the other functions ofcourse.

This is a great article.

I’m trying to make it so the user can only rotate a handle one direction and must be rotated a certain number of times to complete the task (closing a pipe with water in it). To go clockwise I just compare the previous degree to the new degree and if it is greater then update (using your Angle.degFromRot), however, when you get to 359 or 360 you’re stuck as 0 is certainly not greater; plus, if you’re moving the mouse fast you might accidentally skip those high numbers. Do you know of a good way to circumvent this rotation weirdness?

Yay! Thanks for helping me with my maths homework

{ 1 trackback }