Hi. I have a 2D game and I want platforms that rotate between 2 states along the Z.
I want to be able to place the platform at any angle and tell it how many degrees to move (ie:90 or -45).
I want to control it by time (ie: between start and end it will take 3 sec to complete).
I want it to have a constant speed (ie: if its already mid-rotation, it should take half the total duration to complete).
My problem is that it currently works if I leave the starting platform at 0 degrees Z. If I rotate it to other angles, it gets messed up. Maybe you guys can tweak what I have, or maybe I’ve gone about this the wrong way, any help is appreciated!
Here’s what I have:
IEnumerator Turn(Vector3 target)
{
float t = 0;
float tt = duration; //amount of time it should take to go from start to end rotation
Quaternion r = transform.rotation; //current rotation
Quaternion tRot = Quaternion.Euler(target); //target is the eulerAngle I want to reach
Vector3 euler = transform.localEulerAngles;
//Maintains constant speed based on the total duration of time
tt = Mathf.Abs(((Mathf.Abs(target.z) - euler.z)/targetAngle) * duration); //**problem line**
print (tt + " = " + Mathf.Abs(target.z) + " - " + euler.z + " / " + targetAngle + " * " + duration);
while (t < tt)
{
t += Time.deltaTime;
transform.rotation = Quaternion.Lerp(r, tRot, t/tt);
yield return 0;
}
transform.rotation = tRot;
}
This will rotate the object towards _targetRotation at a constant rate of 90 degrees per second. Other code can set _targetRotation however you like.
If you do it with coroutines then I’d still suggest using this construct, and testing Quaternion.Angle to determine when the interpolation is complete. Something like this:
This also has a problem if the Quaternion.Angle == 180. It tends to go clockwise in that case, I haven’t found a way to mitigate this other than changing my rotations ever so slightly to be just above or just below a 180 angle. But this is limiting if, say, I wanted to rotate 270 degrees. It would take the shortest route, not the intended 3/4 turn.
You explicitly said you wanted it to move with constant speed though, which is what this does.
From your second post it sounds like you’d get the result you want from interpolating the vector of Euler angles instead - you can certainly do that, Vector3.MoveTowards works in the same way as Quaternion.RotateTowards and you can feed the interpolated Vector3 through Quaternion.Euler every frame:
If you only want to rotate one axis, Mathf,MoveTowardsAngle is another option, it will always take the shortest route.
e.g.:
var targetAngle:float;
var rotateTime:float; //in seconds
var rotateSpeed:float = Mathf.Abs(targetAngle - transform.localEulerAngles.z)/rotateTime; //calculate rotation speed, degree per second
function Update() {
transform.localEulerAngles.z = Mathf.MoveTowardsAngle(transform.localEulerAngles.z, targetAngle, rotateSpeed * Time.deltaTime);
}