For those of you that haven’t, I’m trying to show on the GUI what the angular difference is between the camera’s Forward and the “body” Forward, in a 2D space of course. What I have so far is:

but I’m stumped as to where to go from there. I know using Vector2.Angle won’t work since the angle will always be positive, which won’t let me set the RectTransform.rotation on the UI indicator correctly since it doesn’t discern between left and right. I did some research on similar questions and it seems the Mathf.Atan2 function is involved but couldn’t find any cases close enough to mine to figure it out.

Thanks for taking the time to read this, and I hope I’ve been clear enough!

The following code returns the signed angle between two Vector3 considering the normal of the surface (here Vector3.up I suppose) :

float SignedAngleBetween( Vector3 a, Vector3 b, Vector3 n )
{
float angle = Vector3.Angle( a, b );
float sign = Mathf.Sign( Vector3.Dot( n, Vector3.Cross( a, b ) ) );
return angle * sign;
}

See this manual page to understand the mathematics principles involved :

To be quick : Cross product between two vectors will return a third vector so that it’s perpendicular to the two others and the three vectors make an “direct basis” (using the left hand rule because Unity uses a left-handed coordinate system)

The dot operation will help determining if the vector calculated just above, and the normal are “in the same direction”. If yes, the angle between a and b is positive (anti clockwise).

With this angle, you will be able to rotate your 2D tank

Ended up figuring it out myself. I’m not sure if it’s the most elegant solution, but it’s 10 lines and works:

if(turret) {
//reduce 3D vectors to 2D since Y is irrelevant
reducedVectorTurret = new Vector2(transform.forward.x, transform.forward.z);
reducedVectorBody = new Vector2(playerBody.transform.forward.x, playerBody.transform.forward.z);
//calculate angular difference
angleDifference = Vector2.Angle (reducedVectorTurret, reducedVectorBody);
//x is + or - depending on whether angle is to left or right
//turretIcon is always pointing Vector2.up, so just apply the
//earlier angular difference to bodyIcon Z rotation directly every frame
if(transform.InverseTransformDirection(playerBody.transform.forward).x < 0)
bodyIcon.eulerAngles = new Vector3(0, 0, angleDifference);
else
bodyIcon.eulerAngles = new Vector3(0, 0, -angleDifference);
}

I have a feeling there’s a way to do this using InverseTransformDirection alone and not calculating the angular difference separately, but working with 2D vectors is much easier to understand and being able to plug the angleDifference into eulerAngles.z directly is a nice touch.