- Home /
Make two sets of objects have same angle between them
For those of you that have played Battlefield 1942, what I'm trying to build is the tank turret-to-body rotation indicator (at the bottom): http://www.realtimerendering.com/erich/bf1942/tankvstank_001.jpg
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:
if(turret) {
Vector2 reducedVectorTurret = new Vector2(transform.forward.x, transform.forward.z);
Vector2 reducedVectorBody = new Vector2(playerBody.transform.forward.x, playerBody.transform.forward.z);
float angleDifference = Vector2.Angle (reducedVectorCam, reducedVectorBody);
}
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!
I made a little diagram to help explain what I'm trying to do even further:
It's pretty easy. Take the rotation of your turret, subtract the rotation of the body. Add rotation to 2D body. Done.
I'll write a longer explanation when I get home so I don't make any + - errors.
Answer by Hellium · Jun 18, 2015 at 02:43 PM
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 :
http://docs.unity3d.com/Manual/UnderstandingVectorArithmetic.html
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
tankBody.GetComponent<RectTransform>().rotation = Quaternion.Euler( 0, 0, signedAngle ) ;
Answer by KaWiz · Jun 18, 2015 at 07:05 PM
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.
this code is a little janky when looking straight up or down because of how rotations work, but the turret's Y is clamped so that's not even possible. at least i didn't have to implement trig functions i barely understand :D
Your answer
Follow this Question
Related Questions
Borderlands 2 style vehicle driving! 1 Answer
Rotate on Z axis 2 Answers
3D Turret Rotation 0 Answers
How to make the turret on your tank turn 0 Answers
Can't Ignore a Layer when raycat 0 Answers