Skip to main content
GameDev.net gamedev.net
🔒 Locked

2D projectile aiming problem with atan and quadrants

Started by santiagopuentep Oct 29, 2010 at 5:33 PM 4 replies 1.8k views
Original Post
santiagopuentep
santiagopuentep
Hi, please help! This is driving me crazy.

I have a cannon and a target. I want to make the cannon shoot at the target tanking into account gravity. The only thing I need to know is the cannon's angle since the initial velocity is fixed.

The problem I have is that atan returns the wrong angles. It seems to be a quadrant problem since atan only returns angles between -PI/2 and PI/2.

The coordinates system has the y axis flipped so -y is up.
The angles are measured clockwise from the -y axis so:

(1) vx = v * -cos(angle)
(2) vy = v * sin(angle)

using the equations of motion:

(3) pfy = p0y + vy * t + 0.5 * g * t^2
(4) pfx = p0x + vx * t

where g is gravity, t is time, p0x and p0y are the position of the cannon and pfx and pfy is the position of the target.

from (4) you get:
(5) t = (pfx - p0x) / vx

Now substituting (1), (2) and (5) in (3) you get a quadratic equation were x = cot(angle) and coefficients a, b and c are as follows:

a = g * (pfx - p0x)^2 / (2 * v * v)
b = -(pfx - p0x)
c = (p0y - pfy) + g * (pfx - p0x)^2 / (2 * v * v)

Then, I find x with the solution to a quadratic equation

(-b +- sqrt(b*b - 4*a*c)) / 2*a

since x = cot(angle) = 1/tan(angle) the angle is found with Math.atan(1/x).

I'm getting weird quadrant problems. The cannon sometimes aims correctly and sometimes it just fires the opposite way.

Does anybody have any idea of what I'm doing wrong?

Thanks in advance.

SP.

Similar problem found in this topic:
http://www.gamedev.net/community/forums/topic.asp?topic_id=560312
kuroioranda
kuroioranda
I think atan2() is what you are looking for. It takes both an x and y parameter so that it can correctly place the angle in all four quadrants. The normal atan function is periodic from -PI/2 to PI/2 (and therefore cannot express angles outside that range) which is probably why you are sometimes firing backwards.

http://en.wikipedia.org/wiki/Atan2
santiagopuentep
santiagopuentep
Thanks kuroioranda.

I don't see how I could use atan2. The value I have is 1/tan(angle), how can I separete the x and y from that?

I really need my tanks working! :)
santiagopuentep
santiagopuentep
I there's this other solution in an other topic, but I says there's 2 solutions for vx when I see 4 of them.

"I tried solving your problem with the following system of equations:
x = vx * t (1)
y = vy * t - 1/2 * g * t² (2)
v²= vx² + vy² (3)

(1) => t = x / vx (4)
(4) in (2) => vy² = ( vx * y / x )² + g * y + ( g * x / ( 2 * vx ) )² (5)
(5) in (3) =>
[ 1 + ( y /x )² ]vx² + ( g * x / 2 )²( 1 / vx )² + g * y - v² = 0
<=>[ 1 + ( y /x )² ]vx⁴ + ( g * y - v² )vx² + ( g * x / 2 )² = 0
=> vx² = 0.5 * [ ( v² - g * y ) +- sqrt( v⁴ - 2 * g * v² * y - g² * x² ) ] / [ 1 + ( y / x )² ] (6)

You get rid of the angle the velocity makes with the x axis. (6) gives you two possibles solution for vx. Compute them, and for each of them compute the corresponding vy. Compute the time t with the first equation. And see between the two triples (vx,vy,t) which one verifies the second equation."

I'm really stuck with this. I was really close with the tan and cot solution but I still can't figure out the quadrants problem!
apatriarca
apatriarca
Since vx is constant,
pfx = p0x + vx * t
which implies
vx = (pfx - p0x)/t.
Since t is positive, vx should have the same sign of (pfx - p0x). This should give you the quadrant. Indeed, if vx is positive, then the angle must be between 0 and pi, it vx is negative, then the angle must be between -pi and 0.

EDIT: Just found this
Quote:

The coordinates system has the y axis flipped so -y is up.
The angles are measured clockwise from the -y axis so:

(1) vx = v * -cos(angle)
(2) vy = v * sin(angle)

I think it should be
(1) vx = v * sin(angle)
(2) vy = v * -cos(angle).
santiagopuentep
santiagopuentep
apatriarca, thanks for the help, that put me on the right track.
About the (1) and (2) equations, I wrote them down wrong but I was using the right ones so the problem was about the quadrants.

Ok, so after a lot of fighting with it I found the solution. I'll post it here for anyone that runs into the same problem.

Since I have the y axis inverted (-y is up) and the angles are measured clockwise from -y I have:

(1) vx = v * sin(angle)
(2) vy = v * -cos(angle)

Where v is the initial velocity of the projectile.

Using the equations of motion:

(3) pfy = p0y + vy * t + 0.5 * g * t^2
(4) pfx = p0x + vx * t

where g is gravity, t is time, p0x and p0y are the position of the cannon and pfx and pfy is the position of the target.

from (4) you get:
(5) t = (pfx - p0x) / vx

Now substituting (1), (2) and (5) in (3) you get a quadratic equation 0 = a*x^2 + b*x + c were x = cot(angle) and coefficients a, b and c are as follows:

a = g * (pfx - p0x)^2 / (2 * v * v)
b = -(pfx - p0x)
c = (p0y - pfy) + g * (pfx - p0x)^2 / (2 * v * v)

To find that quadratic equation one must know that 1 + tan^2 = sec^2 or 1 + cot^2 = csc^2 (search for trigonometric identities on wikipedia)
This post helps too
http://www.gamedev.net/community/forums/topic.asp?topic_id=560312

Then, find x with the solution of a quadratic equation

(-b +- sqrt(b*b - 4*a*c)) / 2*a

since x = cot(angle) = 1/tan(angle) the angle is found with Math.atan(1/x).

From the two solutions you get, the smaller one gives you the shortest path for the bullet (direct hit) and the other one gives the longest path (lob shot).

Now, there are tree problems to solve.

First is when pfx - p0x = 0. You'll get a division by 0. This is when firing straight up or straight down. To solve it find the solution to
(3) only, because all the movement is in the y axis (vx = 0). If there is solution you just need to choose to fire up or down depending on the type
of shot you want ("direct" or "lob").

Second, a quadrant problem that makes you get a "lob" shot on one side of the y axis and a "direct" shot on the other side or viceversa.
To solve it just calculate everything with the target to the right of the cannon and then invert the resultant angle at the end if necessary.

Third, a quadrant problem with "direct" shots when the resultant angle of the cannon needs to be > |PI/2| (remember that the atan is in [-PI/2, PI/2]).
To solve it, just check if the tangent of cotangent si negative. If it is you'll have to add PI or -PI to the angle you get from atan().

That's it.

This solution is pretty fast (1 sqrt() and 1 atan()) and works perfectly but maybe there's something better. If anyone knows a better solution please post it!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.