- Home /
Trouble with Vector3.Angle() and RotateAround()
Hello everyone, I'm scripting a "turret" that looks at a target position (ignoring the Y difference between the two if any).
Unfortunately I've become stuck on a problem where I can never (on purpose) get Vector3.Angle() to be 0. At this point, the value will become close to 0 (say 0.03) then start flipping back and forth between the positive and negative value of that small number) which you can see in the screenshot. Occasionally, the value does become 0, but I don't know why.
I thought that the way I have the relevant part of this script would handle this (in that the desired rotation amount, at a small value, becomes the remainder of the current rotation to 0, meaning the angle should be 0 on the next frame), but obviously it does not.
//check if the Turret has a clear los according to whatever its impassible layers are:
Debug.DrawLine(transform.position, currentTargetPosition, Color.red);
if(!Physics.Linecast(transform.position, currentTargetPosition, impassibleLayer) ) //if raycast dosen't hit anything...
{
if(turretCentered) //update Turret so it knows it is not centered anymore
{
turretCentered = false;
}
//Turret does not care about any Y position differences...
Vector3 currCustom = currentTargetPosition;
currCustom.y = transform.position.y; //ignore Y differences...
Vector3 directionVector = currCustom - transform.position;
float angle = Vector3.Angle(transform.forward, directionVector);
Debug.Log("angle is: " + angle);
float rotAmount = maxRotationSpeed * Time.deltaTime;
Debug.Log("initial rotAmount is: " + rotAmount);
if(Mathf.Abs(angle) - Mathf.Abs(rotAmount) <= 0f) //don't overshoot desired angle (which is 0)...
{
//Debug.Log("RotateTurret() breaking...");
//Debug.Break();
rotAmount = angle; //set rotation amount to the remaining angle...
Debug.Log("rotAmount = angle: " + rotAmount);
}
//now figure out if turret should rotate to the left or right:
if(Vector3.Cross(transform.forward, directionVector).y < 0f)
{
//Debug.Log("cross.y is <= 0f");
rotAmount = -rotAmount;
}
else
{
//Debug.Log("cross.y is > 0f");
}
Debug.Log("final rotAmount is: " + rotAmount);
transform.RotateAround(transform.position, transform.up, rotAmount);
//
Any ideas on what is happening is appreciated, thank you for reading.
Answer by Owen-Reynolds · Mar 03, 2015 at 09:06 PM
I just skimmed the first part and glanced at the script, but: Unity has RotateTowards (and MoveTowards) for just such overshoot problems. Both are written so they will never overshoot, and do nothing if you are at the target.
They aren't complicated, and easy to write yourself (it looks like you did?) but they make code a little nicer. I suspect your overshoot math may have a problem.
RotateTowards always make the one most direct rotation -- it picks the rotation axis itself. Which is often what you really wanted. But, seems you could use MoveTowards directly on your angle
var.
@Owen Reynolds:
"RotateTowards"
In this case, I'm not sure how to use it because it wants 2 Quaternions. I've got one (the turret transform), but I'm not sure how to get the other (since I'm trying to align to a Vec3 position, not another rotation.
"you could use $$anonymous$$oveTowards directly on your angle var"
I'm just not quite sure what you mean there.
Anyway, thank you for the response. It also tried LookAt() just to force a perfect direction, and sometimes angle is still not 0....
Can look all these things up, if you want to, such as "unity convert direction to quaternion." But takes time to learn.
LookAt is a different issue. If it gives you 0.001 for an angle, it's probably correct (and you are a little off-center.) But at least LookAt won't go backNforth if you keep calling it.
Your answer
Follow this Question
Related Questions
Flip over an object (smooth transition) 3 Answers
Having Trouble with Vector3.Angle 1 Answer
Rotating without gimbal lock 1 Answer
Rotating Joystick on Touch 0 Answers