- Home /
Angle of 2 Vector3 on one axis
Hey there!
So this is my situation: I have a classic turret made out of a turretBase (that rotates on Y only) and a turretBody (that rotates on X only) which is a child of the turretBase. The turret is attached to a ship that rotates on all axis.
When I select a target, I want the base to rotate towards it on Y and the body to rotate towards the target on X. I need to do all this using angles, and transform.RotateAround, because I am also imposing limits on the turret (so it does not shoot through the ship).
So my idea for the base was to find the angle between base.forward and the target direction (which is target.position - turretBase.position). The problem is that this angle has to be only in XZ plane (so an Y angle). What I did was this:
var targetDirection = target.position - turretBase.position;
targetDirection.y = turretBase.forward.y;
yAngleToTarget = Vector3.Angle(turretBase.forward, targetDirection);
Well, as expected, that angle is not only on Y, so I can't use it.
So my question is: having 2 Vector3s, how do I get the Y angle between them, relative to the first vector?
Thanks in advance!
PS: I also tried this:
var targetDirection = target.position - turretBase.position;
var angleOnY = Mathf.Asin(Vector3.Cross(targetDirection, turretBase.forward).y) * Mathf.Rad2Deg;
and it works great at times, problem is it often causes an "!IsFinite(outDistanceAlongView)" error. Probably division by 0, somewhere, though I can't be sure.
Answer by Owen-Reynolds · Jul 07, 2013 at 08:22 PM
One note: V3.Angle can't tell left from right.
Sometimes easier to put everything in the turret's local coords. This assumes turretBase has +z pointing the way it shoots:
V3 targDir = targPos - myPos; // your same code
targDir = turretBase.InverseTransformDirection(targDir);
targDir.y = 0; // if you want to get the Y-angle
The hardest part is realizing that targDir
is now using the turret's red/green/blue arrows (with the base as 000.) V3.Angle(V3.forward, targDir
gives the spin around the turrets local green up arrow, AND, can just check if(targDir.x<0)
to get left/right.
Answer by glitchers · Oct 11, 2016 at 03:55 PM
I found this solutions to be locked in a range of -90°-90°
so here's my solution:
var targetDirection = targetPosition - turretTransform.position;
targetDirection = turretTransform.InverseTransformDirection(targetDirection);
var angleOnY = Mathf.Atan2( targetDirection.z, targetDirection.x ) * Mathf.Rad2Deg;
// You may have to +/- 90 to the last angle but this works for me in 360°.
// I use it for directional hit markers in my shooter for turning 3d into 2d screen space
Hope that helps someone as this is the page I found on Google.
You've helped me greatly! I was struggling to get the absolute angles of multiple objects relative to the player on a single axis and this was the answer. Thank you!
Answer by aldonaletto · Jul 07, 2013 at 07:57 PM
The vectors must be normalized for Vector3.Cross to return a value equal to the sine of the angle. Since turretBase.forward already is a normalized vector, you only have to normalize targetDirection :
var targetDirection = target.position - turretBase.position;
var angleOnY = Mathf.Asin(Vector3.Cross(targetDirection.normalized, turretBase.forward).y) * Mathf.Rad2Deg;
This returns a signed angle about the axis Y; if you use Cross().x, the angle returned is about the axis X, and so on.
I tried this, and it seems to stop the error I was getting previously. However, it does not solve my problem...all angles seem to be correct, yet, somehow, the turret is pointing the wrong way. I tried debugging and I couldn't find the error, yet.
Here is the method I use:
float CalculateRotationForBase(Transform target)
{
//set default position if target is null; rotation sign & rotation angle. 180 is the base forward position.
float relativeAngleOfTarget = 180;
int rotationSign = 1;
float rotation = BaseRotationSpeedAngle;
bool targetInDeadZone = false;
//if target is not null, calculate relative angle (local for base) of target.
if(target != null)
{
var targetDirection = target.position - turretBase.position;
var angleOnY = $$anonymous$$athf.Asin(Vector3.Cross(targetDirection.normalized, -turretBase.forward).y) * $$anonymous$$athf.Rad2Deg;
relativeAngleOfTarget = 180 + angleOnY;
}
//calculate relative angle (local for base) of current base position.
var currentInEuler = turretBase.localEulerAngles.y;
//if target is in the dead zone, calculate which dead zone edge is closer to target.
if(relativeAngleOfTarget <= baseArcAngleStart)
{
relativeAngleOfTarget = baseArcAngleStart;
targetInDeadZone = true;
}
else if(relativeAngleOfTarget >= baseArcAngleEnd)
{
relativeAngleOfTarget = baseArcAngleEnd;
targetInDeadZone = true;
}
//calculate spin direction.
if(relativeAngleOfTarget < currentInEuler)
{
rotationSign = -1;
}
//calculate angle between target and base.
var alpha = $$anonymous$$athf.Abs((360 - relativeAngleOfTarget) - (360 - currentInEuler));
//reduce roatation speed if turret is locked on target OR it is at the edge of the dead zone. This reduces jump oscilation.
baseIsAtEdgeOfDeadZone = targetInDeadZone && alpha < baseBuffer;
if(isLockedOnTarget || baseIsAtEdgeOfDeadZone)// || bodyIsAtEdgeOfDeadZone)
{
rotation = alpha;
}
//if there is no target, and turret is in default position stop shaking.
if(alpha < baseBuffer)
{
if(target == null)
{
rotation = 0;
}
else if(!isLockedOnTarget)
{
rotation = alpha;
}
}
//calculate final rotation.
rotation = rotation * rotationSign;
return rotation;
}
The method takes the target transform, and should return the angle to rotate on Y. I use it like this:
void RotateBase (Transform target)
{
var angleToRotate = CalculateRotationForBase(target);
var verticalAxisDown = turretBase.TransformDirection(Vector3.down);
turretBase.RotateAround(turretBase.position, verticalAxisDown, angleToRotate * Time.deltaTime);
}
Here is a screenshot of the behavior I am getting. The red line is the target direction, and the green one is the turretBase forward. As you see, the error in ai$$anonymous$$g varies with the turret-to-target angle.
Don't think this helps a lot, but maybe you spot something.
Your answer
Follow this Question
Related Questions
How can I rotate a tank's turret back to the starting turret position? 2 Answers
Angle between Ray and Normal 1 Answer
Rotating Turret Base and Barrel 3 Answers
Mesuring distance through script 2 Answers
3D nested Turret Prefab Rotation 1 Answer