Interoperability
As you've pointed out, Unity's API already picks a side by using left-handed coordinates and treating the z rotation angle as being about the positive z axis. So several methods of the
Transform,Rigidbody2D, andVector*/Quaternionmath classes all agree that a positive z angle rotates counter-clockwise (from the default camera viewpoint).
If we "go with the flow" then we have one less exception or special rule to remember, and fewer corrective adjustments to apply. Let's say you need to coordinate the movement of several objects of different types in your game, based on the change in angle of another vector:
`float myAngleDelta = Vector2.SingedAngle(oldReferenceVector, newReferenceVector);`
If we use Unity's convention, we can plug this value straight through into our custom method:
`Vector2 newAimVector = aimVector.Rotate(myAngleDelta);`
And we can also apply this very same value to all our other operations, without needing to negate/adjust it:
Transform aimReticle = GetReticle();
reticle.Rotate(0, 0, myAngleDelta);
Rigidbody2D tank = GetTank();
tank.MoveRotation(tank.rotation + myAngleDelta);
Quaternion twist = Quaternion.Euler(0, 0, myAngleDelta);
Vector3 newAim3D = twist * aim3D;If we "go with the flow" then we have one less exception or special rule to remember, and fewer corrective adjustments to apply. Let's say you need to coordinate the movement of several objects of different types in your game, based on the change in angle of another vector:
float myAngleDelta = Vector2.SignedAngle(oldReferenceVector, newReferenceVector);
If we use Unity's convention, we can plug this value straight through into our custom method:
Vector2 newAimVector = aimVector.Rotate(myAngleDelta);
And we can also apply this very same value to all our other operations, without needing to negate/adjust it:
Transform aimReticle = GetReticle();
reticle.Rotate(0, 0, myAngleDelta);
Rigidbody2D tank = GetTank();
tank.MoveRotation(tank.rotation + myAngleDelta);
Quaternion twist = Quaternion.Euler(0, 0, myAngleDelta);
Vector3 newAim3D = twist * aim3D;
- Mathematical Convention
Mathematical Convention
This also happens to agree with the way angles are conventionally described in a mathematical context. When working with the unit circle or polar coordinates, we say a 2D vector has the form...
$$\vec v = r \cdot \left( \cos \theta , \sin \theta \right)$$
(or if you want to get fancy)
$$x + i y = r \cdot e ^ {i \theta}$$
...where theta is an angle counter-clockwise from the positive x-axis.
This gives us a different kind of interoperability: we now match the bulk of math formulas we might find on the net or in a textbook about how to compute particular angles we care about. So we can convert them clearly into code without extra correction factors (besides the often-unavoidable conversion to & from radians)
One such formula in particular is so common it's baked right into the standard
MathorMathfclasses of many languages/environemnts:float radianAngle = Mathf.Atan2(vector.y, vector.x);Atan2(y, x), when used as directed, converts from a vector to an angle measured counter-clockwise from the positive x-axis. Once again, going with the flow helps you keep compatibility with the bulk of what's already out there.
This also happens to agree with the way angles are conventionally described in a mathematical context. When working with the unit circle or polar coordinates, we say a 2D vector has the form...
$$\vec v = r \cdot \left( \cos \theta , \sin \theta \right)$$
(or if you want to get fancy)
$$x + i y = r \cdot e ^ {i \theta}$$
...where theta is an angle counter-clockwise from the positive x-axis.
This gives us a different kind of interoperability: we now match the bulk of math formulas we might find on the net or in a textbook about how to compute particular angles we care about. So we can convert them clearly into code without extra correction factors (besides the often-unavoidable conversion to & from radians)
One such formula in particular is so common it's baked right into the standard Math or Mathf classes of many languages/environemnts:
float radianAngle = Mathf.Atan2(vector.y, vector.x);
Atan2(y, x), when used as directed, converts from a vector to an angle measured counter-clockwise from the positive x-axis. Once again, going with the flow helps you keep compatibility with the bulk of what's already out there.
