Take the 2-minute tour ×
Mathematics Stack Exchange is a question and answer site for people studying math at any level and professionals in related fields. It's 100% free, no registration required.

This might, perhaps, be more suited to Stack Overflow or the Gaming section, but since it's math that is above my head, I thought I'd come straight here for it.

I'm making a space game. So far I have a spaceship that has a maximum velocity (kept in check by a function that finds the hypotenuse of the triangle made by its vx and vy and ensures that the length of the hypotenuse never surpasses the max_speed), and proper acceleration implemented (as well as proper tracking of angle of rotation in order to generate the vx and vy values). It flies quite nicely. What I'm having trouble with is finding the current angle of motion, as opposed to the current angle the ship is facing.

I know that, for a right triangle, I can find the theta (angle/slope) by calculating the arctangent of the length of the opposite side divided by the length of the adjacent side. In my game, this translates to: Math.atan(vy/vx). The only problem is that it only outputs a result between -90 and 90. I know that's how it's supposed to work (based on what I know about the unit circle, etc.), and so I'm stumped. I can't seem to figure out a way to do what I need to do.

Here are two specific examples of troublesome results: -when vx is 1 and vy is 1, I get atan(1) = 45 -when vx is -1 and vy is -1, I get atan(1) = 45

And so therein lies the heart of the issue. The ship could be moving in the exact opposite direction and it would give me the same angle.

I was thinking of writing a function to modify the output depending on which quadrant the motion was facing. For instance: if vx and vy were both negative, then the angle should be between 270 and 360, or if they were both positive, between 90 and 180. The only issue is the reflection of the result across the axes. I rotate clockwise from 0 degrees, and it counts down from 90 to 0, then down to -90 when I reach the 180 mark, then back up from -90 to 0 as I approach 270, and from 0 to 90 as I pass 270 and on to 360.

Is there any formula I can use, into which I can input my current x speed and y speed, and receive the angle, between 0 and 359 (or 1 and 360, whichever works)? By the way, for my purposes, 0/360/2pi is oriented directly up, 12 o'clock, facing the top edge of the screen.

I have looked all over Google all day long for "rigid body dynamics," "kinematics," and any of a number of other keywords I could think of or find to help find a viable solution -- and I have read countless articles and forums threads about related subjects -- but it appears as though nobody has ever asked or answered this question on the internet (I'm sure it's out there someplace and I'm just too dense or unlucky to find it).

I have read these, too:

http://chrishecker.com/images/d/df/Gdmphys1.pdf

Calculating an Angle from 2 points in space

Help with calculating the angle to turn towards a target in a coordinatesystem

This one almost answered my question, but I'm not entirely sure how to work with it:

Angle for pointing at a certain point in 2d space.

I tried implementing the last suggestion from that thread like so: reverse_angle = roundNumber(radToDeg(Math.cos(vy / (Math.sqrt((vx * vx) + (vy * vy))))),0); but it just gave me angles between 0 and 90, which really wasn't too helpful.

To simplify the question, I'm basically looking for a way to turn the ship to face exactly opposite its current vector, so I can simplify the deceleration process (which I will put to use in the AI when I get to that part, but it's also part of the control scheme: pressing the down arrow reverses your angle as a form of deceleration autopilot to help newbies adjust to unassisted 2D Newtonian spaceflight).

Oh, my. Look at the time. I have to wake up for work in four hours. Goodnight for now!

Thank you very much.


...and here's my current project with the changes in place:

http://adrian.thomas-prestemon.com/game/v3

There is still a bug in the max_speed section of the code, which I hadn't noticed before, but I'll work on that in my own time, or maybe post it to stackoverflow, since it doesn't really belong here. This bug happens when you're accelerating in any given direction, and then rotate while accelerating. Somehow the ship's speed escapes the boundaries I placed on it, and then there is no way to get the speed back below the maximum. Oops. :P

share|improve this question
    
I only clicked your links after answering. Ross's answer at math.stackexchange.com/questions/14177/… should answer your question, modulo converting to degrees and possible adding or subtracting $360^\circ$ to get in the preferred range. –  Jonas Meyer May 24 '11 at 8:35
    
What programming language is this? In the C and C++ maths libraries, there are specializes atan2 functions, which do exactly what you need here. –  leftaroundabout May 24 '11 at 12:17
    
@leftaroundabout - I'm doing this in JavaScript on HTML5 Canvas. It does have an atan2 function, which, despite having read about it, I forgot to try. :P Using atan2, I came up with another working solution, again not very elegant, but it returns the opposite angle of the current ship motion, which is what I need. I now have two working possibilities, both of them ugly but functional. Example will be in next comment due to comment length restrictions. Thank you, Jonas Meyer and leftaroundabout very much for your time and assistance. :D –  Adrian May 24 '11 at 19:00
    
function getAngle2(dx,dy) { var dx = dx; var dy = dy; var angle; if (dx == 0 && dy == 0) { return 0; } if (dy == 0 && dx != 0) { return 90; } if (dy <= 0) { angle = radToDeg(Math.atan2(dy,-dx)); if (dx >= 0) { if ((-angle - 90) == 0) { return 360; } else { return -angle - 90; } } if (dx < 0) { return -angle + 270; } } if (dy > 0) { return radToDeg(Math.atan2(dy,dx)) + 90; } } –  Adrian May 24 '11 at 19:01

1 Answer 1

up vote 5 down vote accepted

Check the sign of $v_x$. If it is less than zero, your direction of motion is $\displaystyle{180^\circ+\arctan\left(\frac{v_y}{v_x}\right)}$. If it is greater than zero, then $\displaystyle{\arctan\left(\frac{v_y}{v_x}\right)}$ works. If it is zero, you're at $\pm 90^\circ$, and the sign of $v_y$ tells you which. If you care about being between $0$ and $360^\circ$ or some other particular range, you can just test the result and add or subtract $360^\circ$ as appropriate.

See this Wikipedia article on a 2-argument arctangent function that exists exactly for this purpose.

You say that angle $0$ is "up" for your purposes. If by this you mean the positive $y$ direction, then you should subtract $90^\circ$ from the result obtained from the above, before testing to see if the angle is in the correct range. The reason is that standard positions of angles, in accordance with the arctangent computations you mentioned, measure the angles counterclockwise from the positive $x$-axis. If you instead measure counterclockwise from the positive $y$-axis, then your starting point is shifted up $90^\circ$, so your angles will correspondingly be shifted down $90^\circ$. (Or you could just apply the above with $v_y$ in place of $v_x$ and $-v_x$ in place of $v_y$, but this might be a bit confusing.)

share|improve this answer
    
This method seems to work pretty well, even though I have to use multiple "if" checks. My code looks like this [it may look a little weird because left is -x, right is +x, up is -y, and right is y, thanks to the screen coordinates being based off the top left corner being (0,0) -- and also because I have it returning the opposite of the angle of motion, so I can just tell the ship to rotate to that angle directly]: (coe in next comment due to length limit) –  Adrian May 24 '11 at 17:36
    
function getAngle(dx,dy) { var dx = dx; var dy = dy; var ang = radToDeg(Math.atan(dy/dx)); if (dx == 0) { if (dy > 0) { return 180; } else { return 360; } } if (dx > 0) { return 90 + ang; } if (dx < 0) { return 270 + ang; } } –  Adrian May 24 '11 at 17:36

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.