Solution using Modulo
A simple solution that catches all cases.
degrees = (degrees + 360) % 360; // +360 for implementations where mod returns negative numbers
Explanation
Positive: 1 to 180
If you mod any positive number between 1 and 180 by 360, you will get the exact same number you put in. Mod here just ensures these positive numbers are returned as the same value.
Negative: -180 to -1
Using mod here will return values in the range of 180 and 359 degrees.
Special cases: 0 and 360
Using mod means that 0 is returned, making this a safe 0-359 degrees solution.
Answer from Liam George Betsworth on Stack OverflowSolution using Modulo
A simple solution that catches all cases.
degrees = (degrees + 360) % 360; // +360 for implementations where mod returns negative numbers
Explanation
Positive: 1 to 180
If you mod any positive number between 1 and 180 by 360, you will get the exact same number you put in. Mod here just ensures these positive numbers are returned as the same value.
Negative: -180 to -1
Using mod here will return values in the range of 180 and 359 degrees.
Special cases: 0 and 360
Using mod means that 0 is returned, making this a safe 0-359 degrees solution.
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)
You can multiply the result by (180/pi) to convert the magnitude to degrees. If it's negative then you would have to add 360 to it afterwards (assuming you want a range of 0 to 360.)
For example, -pi/2 becomes -90 after the multiplication, and adding that to 360 results in 270, which gives you the amount of degrees to rotate counter-clockwise from the positive x-direction to reach the point (which is what you're looking for I think.)
You can add 180 to your converted result to give a range of 0 to 360.
math - Convert atan2 value to standard 360-degree-system value - Stack Overflow
mathematics - How does atan2 work when getting angle of a vector? - Game Development Stack Exchange
Highest scored 'atan2' questions - Stack Overflow
How to achieve 360 degree display using arctangent by case structure?
From the Wikipedia page:
It is returning the shortest angle of rotation from the positive x direction to the point, where a positive angle indicates the counter-clockwise direction. Therefore it makes sense that it would only return values between 0 and 180, since anything greater than 180 can be 'better' approached by a smaller angle in the opposite direction.
Returning -90 instead of 270 also makes sense now, since moving 90 degrees clockwise is less than moving 270 degrees counter-clockwise to reach the same point. This also suggests that your interpretation has mixed up the positive and negative 90 degree directions but is otherwise fine.
The referenced Wikipedia article provides the logic of the atan2 function, which has been optimized computationally (it works faster than implementing the statement explicitly). To convert to 0-to-360 degree values, first you must adjust the range of atan2 results, then convert to degrees, shown here as a vectorized operation in pseudo-code:
rad = atan2(y,x)
rad[rad < 0] = rad[rad < 0] + 2*pi
deg = rad*(180/pi)
Hope that is helpful.
Hi everyone,
in my top-down 2D project I have a submarine that can rotate and move around the map. I would like to find the bearing to another 2D object, such as a ship. The 0 bearing is to the front of the submarine (its bow, or "nose"), the 90 bearing is to its right, 270 is to its left, and 180 is directly behind it, like this:
However, whenever the submarine turns, the code should reflect this, and update the bearing, and return a number like this:
The code I pasted below sort of works: it returns a bearing that is close to what it should be, BUT only when the player submarine is stationary. As soon as it starts to move, the values do not change as they should. Also, it's intended for 3D.
float angle = Quaternion.FromToRotation(Vector3.right, target.position - player.position).eulerAngles.z;
I've also found this code at this link (https://answers.unity.com/questions/434657/given-starting-transform-and-target-position-how-t.html), which I've been unable to adapt to 2D so far. I'm not sure how to refactor it.
// Takes a starting object's Transform, and a target object's position, and returns the angle to the target 0-359°
public float GetBearing(Transform startTransform, Vector3 targetPosition) {
Vector3 vectorToTarget = targetPosition - startTransform.position;
float angleToTarget = Vector3.Angle(startTransform.right, vectorToTarget);
int direction = AngleDir(startTransform.right, vectorToTarget, startTransform.up);
return (direction == 1) ? 360f - angleToTarget : angleToTarget;
return angleToTarget;
}
int AngleDir(Vector3 forwardVector, Vector3 targetDirection, Vector3 upVector) {
float direction = Vector3.Dot(Vector3.Cross(forwardVector, targetDirection), upVector);
if (direction > 0f) {
return 1;
} else if (direction < 0f) {
return -1;
} else {
return 0;
}
}
I'd appreciate any ideas.