[Math] How to find angle of motion in frictionless space based on vx and vy

physicstrigonometryvector-spaces

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. 😛

Best Answer

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.)

Related Question