Can't rotate on x z axis via script...

I am sure this is an issue due to quaternions or the like, but…

In an attempt to get a jump on something, I was working on a snippet of code, and was trying to rotate a cube with a script so that the cube would rotate 180* every time the user clicked the cube, but couldn’t effect the cube while it was rotating.

At first I thought I’d just lerp the axis, and protect the cube with an If() until it was done rotating.

cube.transform.rotation.AXIS(x,y,or z) = Mathf.Lerp(originalAngle, targetAngle, (Time.time - startTime) * turnSpeed);
if ((targetAngle - cube.transform.rotation.AXIS(x,y,or z)) < 3.0 || (targetAngle - cube.transform.rotation.AXIS(x,y,or z)) > 357.0 )
(Where "AXIS(x,y,or z)" is the axis of choice. e.g.: cube.transform.rotation.y)

It works on the y-axis, but on the x- and z-axes, the way that Unity interprets the rotation into the discreet axes causes problems.

To take the x for example - If you start with transform = (0,0,0) and try to rotate on the x through to tranform = (180, 0,0), when x > 90*, Unity resets y z to 180* and x counts DOWN from 90* back to 0*.

Ratz.

If however, I accept this new transform rotation of 0,180,180 as teh NEW start position for the second rotation and try to lerp again from x=0 to x=180, Unity pops the transform rotation back to 0,0,0 from 0,180,180 just by using x = 0. So - somewhere Unity is remembering (even tho’ it’s displaying and using 0,180,180) that I was only effecting the x-axis, and reverts back to what it was…

The crux to this problem is trying to test when the operation is finished, and how to do it again on a second click. The first time always works fine in the ROTATE lerp. What happens tho’ is it never detects the end of the rotation, because it never reaches it’s goal position.

If (as is shown below), I just end the rotation based on time, I can’t get the second rotation target to work correctly because of the reset of the rotation.

I’ve tried the transform, quaternions, euler angles… pretty much all shots in the dark.

Can anyone suggest a better way of doing this?

var cube : GameObject;
var turnSpeed : float = 2.0;
private var startTime : float;
private var originalAngle : float;
private var targetAngle : float;
private var canRotate : boolean = true;
private var rotating : boolean = false;

function OnMouseUp () {
	if (canRotate) {
		canRotate = false;
		startTime = Time.time;
		originalAngle = cube.transform.rotation.x;
		targetAngle = cube.transform.rotation.x + 180;
		rotating = true;
	}
}

function Update () {
	if (rotating) {
		cube.transform.rotation.x = Mathf.Lerp(originalAngle, targetAngle, (Time.time - startTime) * turnSpeed);
//		if ((targetAngle - cube.transform.rotation.AXIS(x,y,or z)) < 3.0 || (targetAngle - cube.transform.rotation.AXIS(x,y,or z)) > 357.0 )
		if ((Time.time - startTime) > 0.55) {
			cube.transform.rotation.x = Mathf.Round(targetAngle);
			canRotate = true;
			rotating = false;
		}
	}
}

This is the unedited code that’s mid-test with some other attempts including the euler angles… Pretty much junk:

var cube : GameObject;
var turnSpeed : float = 2.0;
private var startTime : float;
private var originalAngle : float;
private var targetAngle : float;
private var canRotate : boolean = true;
private var rotating : boolean = false;

function OnMouseUp () {
	Debug.Log ("Rotating: " + rotating);
	Debug.Log ("canRotate: " + canRotate);
	if (canRotate) {
		canRotate = false;
		startTime = Time.time;
		originalAngle = cube.transform.rotation.x;
		targetAngle = cube.transform.rotation.x + 180;
//		targetAngle = cube.transform.rotation.eulerAngles + Vector3(0, 180, 0);
		rotating = true;
	}
	Debug.Log ("currentAngle: " + cube.transform.rotation.x);
	Debug.Log ("targetAngle: " + targetAngle);
//	Debug.Log ("currentAngle: " + cube.transform.rotation.y);
//	Debug.Log ("targetAngle: " + targetAngle);
	Debug.Log ("------------------------------------------------------");
}

function Update () {
	if (rotating) {
		cube.transform.rotation.x = Mathf.Lerp(originalAngle, targetAngle, (Time.time - startTime) * turnSpeed);
//		cube.transform.rotation = Quaternion.AngleAxis(Mathf.Lerp(originalAngle, targetAngle, (Time.time - startTime) * turnSpeed), Vector3.right);
		if ((Time.time - startTime) > 0.55) {
			cube.transform.rotation.x = Mathf.Round(targetAngle);
//		if ((targetAngle - cube.transform.rotation.x) < 3.0 || (targetAngle - cube.transform.rotation.x) > 357.0 ) {
//			cube.transform.rotation.x = 0.0;
//			cube.transform.rotation.x = Mathf.Round(targetAngle);
//		if ((targetAngle.y - cube.transform.rotation.eulerAngles.y) < 3.0 || (targetAngle.y - cube.transform.rotation.eulerAngles.y) > 357.0 ) {
//			cube.transform.rotation.eulerAngles.y = Mathf.Round(targetAngle.y);
			canRotate = true;
			rotating = false;
		}
	}
}

There exists a function on the transform for this you know? Avoid dealing directly with quaternions at all cost :!:

To rotate around the x-axis do:
transform.Rotate( Vector3.right, angle );

Ah - that’ll be it then, no?

The Rotate method is great if you just want some rotation and it is not so important how the object is aligned exactly after the rotation is done.

However, if you want a very precise rotation over some amount of time and it is important to end with a specific alignment, I would still recommend working in absolute rotations rather than rotation changes. The AngleAxis method is good for doing rotations about any axis:

cube.transform.rotation =
Quaternion.AngleAxis(
   Mathf.Lerp(0, 180, (Time.time - startTime) * turnSpeed),
   Vector3.right // around x-axis
);

Rune