Converting 2 Axis Input to an Angle

  • Thread starter Thread starter Drakkith
  • Start date Start date
  • Tags Tags
    Angle Axis Input
Drakkith
Mentor
Messages
23,175
Reaction score
7,625
I'm dabbling in video game creation and I'm making a very basic top-down twin stick shooter. The problem is that I don't know how to get the player to turn to an angle that matches the controller's right stick. I'm trying to figure out an equation or something to convert the -100 to +100 input from each axis of the stick into a degree measurement to turn the player towards.

For example, if the stick is at a coordinate of (50,50), up and right, then the player would turn to 315 degrees (0 degrees is at the 3 O-clock position in the program I'm using and moves clockwise from there).

Any ideas?
 
Mathematics news on Phys.org
Usually, 0o is on the x-axis (3 o'clock position as yours) but the angle moves anticlockwise. In this setting, to find the angle given some coordinate (x,y), where x>0, all we need to do is to compute

\theta = \tan^{-1}\left({\frac{y}{x}}\right)

And the result will be in radians. But now since your system is a clockwise rotation, just take the negative of that value.
Notice that I said for x>0. We run into problems when trying to distinguish, say, (50,50) with (-50,-50) because y/x = 1 in both of these cases while they obviously differ by 180o. We also have another problem. The arctan function we're using returns values between -90o and 90o. Basically, the coordinate (50,50) will return -45o as opposed to 315o which is a whole revolution more.

So let's consider consider the 4 points A,B,C,D where each point is in its respective quadrant starting with A in the lower right, so if we consider their angles to be
$$A=70^o$$
$$B=110^o=180^o-70^o$$
$$C=250^o=180^o+70^o$$
$$D=290^o=360^o-70^o$$

Then we know that the inverse tan function would return A = 70o, B = -70o, C = 70o, D = -70o so you'll need to account for these discrepancies accordingly.
 
Thanks, Mentallic. I should be able to make two different events to control the players angle, one for when X > 0 and one for when X < 0. How would that change our math?
 
So if X > 0 and Y < 0 (bottom right) then the angle is simply the value returned by the arctan calculation. If X < 0 then we add 180 to the calculation. Finally, if X > 0 and Y > 0 then we add 360.

The code to return the angle could be...

edit: I decided not to post any code in case you want to make the discovery for yourself.
 
Thanks, guys. I'll try to implement this as soon as possible and get back to you.
 
Got it. Had to figure out a few things regarding which axis was which and in what direction the values increased or decreased, but I worked it out. In my program I have to enter the following events:

System: Every tick
----Gamepad: Gamepad 0 Right Analog X axis > 0
--------Gamepad: Gamepad 0 Right Analog Y Axis < 0 : Player: Set Angle to 360+atan((Gamepad.Axis(0,3))/(Gamepad.Axis(0,2)))
--------System: Else : Player: Set angle to atan((Gamepad.Axis(0,3))/(Gamepad.Axis(0,2)))
----Gamepad: Gamepad 0 Right Analog X Axis < 0
--------Gamepad: Gamepad 0 Right Analog Y Axis not equal to 0 : Player: 180-atan((Gamepad.Axis(0,3))/(Gamepad.Axis(0,2)))

Thanks you two. I couldn't have done it without you.
 
Last edited:
Drakkith said:
System: Every tick
----Gamepad: Gamepad 0 Right Analog X axis > 0
--------Gamepad: Gamepad 0 Right Analog Y Axis < 0 : Player: Set Angle to 360+atan((Gamepad.Axis(0,3))/(Gamepad.Axis(0,2)))
--------System: Else : Player: Set angle to atan((Gamepad.Axis(0,3))/(Gamepad.Axis(0,2)))
----Gamepad: Gamepad 0 Right Analog X Axis < 0
--------Gamepad: Gamepad 0 Right Analog Y Axis < 0 : Player: 180-atan((Gamepad.Axis(0,3))/(Gamepad.Axis(0,2)))
--------System: Else : Player: Set Angle to 180+atan((Gamepad.Axis(0,3))/(Gamepad.Axis(0,2)))

A few possible bugs I've noticed.

Have you considered when X=0? The atan calculation will cause problems because you're dividing by zero, but the angle will simply be 90 and 270 deg respectively depending on Y (also assuming X!=0 && Y!=0).
Also I see you're calculating 360+angle for the lower right axis (X>0, Y<0) as opposed to upper right, is this intended?
For X<0, the calculation -atan(Y/X) is 180 degrees short for both Y<0 and Y>0, so you should be calculating 180-atan(Y/X) in both of these.
Finally, the atan(Y/X) result is in radians, and you're adding degrees to it. You need to convert it to degrees first by multiplying -atan(Y/X) by 180/pi, and then do your degree addition.

Here is a sample code in C:
float angle;
assert(X!=0 && Y!=0);

if (X=0 && Y<0)
- - - angle = 90;
else if (X=0 && Y>0)
- - - angle = 270;
else {
- - - float gradient = ((float)Y)/X;
- - - angle = -atan(gradient)*180/pi;
- - - if (X<0)
- - - - - - angle += 180;
- - - else if (Y>0)
- - - - - - angle += 360;
}

return angle;
 
Mentallic said:
Have you considered when X=0?

The code only runs the event when X is greater than or less than zero. When X = 0 the event doesn't run, so it is never calculated. I've done some a small amount of testing, so I can't tell if it works perfectly yet, but it appears to work very well overall.

Also I see you're calculating 360+angle for the lower right axis (X>0, Y<0) as opposed to upper right, is this intended?

Yes. My controller's right analog stick goes from 0 to -100 when pressed upwards and 0 to +100 when pressed downwards. It threw me off for a while until I figured that out.

For X<0, the calculation -atan(Y/X) is 180 degrees short for both Y<0 and Y>0, so you should be calculating 180-atan(Y/X) in both of these.

Why's that? If X = -90 and Y = 2, then atan(2/-90) equals -1.273. Adding 180+atan(2/-90) gives me 178, which is the degree I need.

Finally, the atan(Y/X) result is in radians, and you're adding degrees to it. You need to convert it to degrees first by multiplying -atan(Y/X) by 180/pi, and then do your degree addition.

The program I use calculates everything in degrees, no radians. It works. I've tested it and my player's sprite turns to match the angle of the stick very well.
 
  • #10
Drakkith said:
Why's that? If X = -90 and Y = 2, then atan(2/-90) equals -1.273. Adding 180+atan(2/-90) gives me 178, which is the degree I need.

If X = -90 and Y = 2 then that's the top-left quadrant which is 180 and a bit, so you don't want 178 degrees but rather 182 degrees.

But of course, you're the one that's familiar with the system you're using and if you claim it works then why would we try and fix something that isn't broken? ;)
 
  • #11
Mentallic said:
If X = -90 and Y = 2 then that's the top-left quadrant which is 180 and a bit, so you don't want 178 degrees but rather 182 degrees.

This would be true if my controller returned a positive Y-value when the stick is pressed upwards, but it doesn't. When the stick is pressed up it returns a negative value. So pressing it halfway up returns a value of -50.

This took me about one or two infuriating hours to figure out. The math was telling me my code should work, but when I first implemented it, the player's sprite turned everywhere but the right direction!
 
  • #12
Ack! I did make a mistake. I had one of one of my conditions set up to check for the Left analog Y-axis, instead of the Right analog stick Y-axis. Turns out that when X<0 I can simply have one condition for when Y is not equal to zero that will then set the player angle to 180+atan(y/x) and it will work perfectly for when the Y-axis is either negative or positive.
 
  • #13
Oh I see, so really, you just want to calculate atan(Y/X) as opposed to -atan(Y/X) because Y is replaced by -Y, and -atan(-Y/X) and in this case, you can bring the negative within the argument out and we end up with atan(Y/X). So the way you've constructed where to start your angle 0o and to rotate clockwise is equivalent to the standard way it is done in maths.
So we do

angle = atan(y/x);
if (x<0)
- - - angle += 180;
else if (y<0)
- - - angle += 360;
return angle;
 
  • #14
I think that's what's going on. All I know is that it works, lol.
 
Back
Top