- Home /
Smooth rotation in 90° increments
I have a puzzle in my game where there is a painting on a wall. The painting is broken up into a 4x6 grid of cubes (only one face of each is visible), and each cube is rotated on the x axis so that the image is scrambled.
The goal of the puzzle is to rotate each of the pieces until the picture is properly formed.
I know how to make the puzzle work, but not exactly the way I wanted to.
I was trying to make it so that each time a cube was clicked, it rotated 90° a second and stopped at each 90° increment.
Of course, Euler angles are all funky so I was having a hard time getting it to work properly, so I just have them instantly rotating 90° each click.
The code I was using while trying to make a smooth rotation is as follows:
var rotationState: boolean = false;
function OnMouseDown(){
rotationState = true;
}
function Update () {
if (rotationState == true && transform.eulerAngles.x >=0 && transform.eulerAngles.x < 90){
transform.Rotate(90 * Time.deltaTime, 0, 0);
if (transform.eulerAngles.x >= 90){
rotationState = false;
}
} else if (rotationState == true && transform.eulerAngles.x >=90 && transform.eulerAngles.x < 180){
transform.Rotate(90 * Time.deltaTime, 0, 0);
if (transform.eulerAngles.x >= 180){
rotationState = false;
}
} else if (rotationState == true && transform.eulerAngles.x >= 180 && transform.eulerAngles.x < 270){
transform.Rotate(90 * Time.deltaTime, 0, 0);
if (transform.eulerAngles.x >= 270){
rotationState = false;
}
} else if (rotationState == true && transform.eulerAngles.x >=270 && transform.eulerAngles.x < 360){
transform.Rotate(90 * Time.deltaTime, 0, 0);
if (transform.eulerAngles.x >= 360){
rotationState = false;
}
}
}
The code worked for the first two clicks, and then the rotations started to get strange.
Does anyone have any idea how I can achieve the desired effect?
Answer by robertbu · Mar 25, 2014 at 03:26 AM
There are lots of ways to do what you want in Unity. Here is one. It requires that you set 'vCurr' to the starting rotation in the Inspector.
#pragma strict
var speed = 90;
var vCurr : Vector3 = Vector3.zero;
private var vNew : Vector3 = Vector3.zero;
function Start() {
transform.eulerAngles = vCurr;
vNew = vCurr;
}
function Update() {
vCurr = Vector3.MoveTowards(vCurr, vNew, speed * Time.deltaTime);
transform.eulerAngles = vCurr;
}
function OnMouseDown() {
if (vCurr == vNew)
vNew.x += 90.0;
}
Here is a second one. It is a relative rotation using Quaternions. It is a bit harder to understand than the first one, but it does not require setting the rotation in the inspector.
#pragma strict
var speed : float = 90.0;
private var qTo : Quaternion;
function Start() {
qTo = transform.rotation;
}
function Update () {
transform.rotation = Quaternion.RotateTowards(transform.rotation, qTo, speed * Time.deltaTime);
}
function OnMouseDown() {
if (transform.rotation == qTo)
qTo = Quaternion.AngleAxis(90.0, Vector3.right) * qTo;
}
Both work perfectly! Thank you!
I would like to use something similar to the first example you've provided, but I HATE using code that I don't fully understand.
I fully understand everything except for the Vector3.$$anonymous$$oveTowards.
The documentation makes it seem like this is generally used for movement, not rotation. Could you let me know if the following explanation is correct, and clarify if not?
Vector3.$$anonymous$$oveTowards returns a Vector3 value that is equal to the current rotation/position incremented by speed Time.deltaTime. However, if the value to be returned by Vector3.$$anonymous$$oveTowards exceeds the target value passed to* Vector3.$$anonymous$$oveTowards, the target value will be returned ins$$anonymous$$d.
By changing vCurr to Vector3.$$anonymous$$oveTowards(vCurr, vNew, speed * Time.deltaTime) each frame and setting the object's rotation equal to vCurr, a smooth rotation effect is achieved.
Is my understanding at least somewhat sound?
Also, you mentioned that the second script example doesn't require that I initialize vCurr in the Inspector.
Would the following modified version of your first script also do the trick, or is there a flaw I'm not seeing? (Lines 4 and 9 have been modified)
#pragma strict
var speed = 90;
private var vCurr : Vector3 = Vector3.zero;
private var vNew : Vector3 = Vector3.zero;
function Start() {
vCurr = transform.eulerAngles;
vNew = vCurr;
}
function Update() {
vCurr = Vector3.$$anonymous$$oveTowards(vCurr, vNew, speed * Time.deltaTime);
transform.eulerAngles = vCurr;
}
function On$$anonymous$$ouseDown() {
if (vCurr == vNew)
vNew.x += 90.0;
}
Thanks a bunch!
What you are trying to do with the script in the second comment has an issue. You are reading eulerAngles:
vCurr = transform.eulerAngles;
The problem is that there are multiple euler angle respresentations for any given physical rotation, and Unity may elect to give you one you don't expect. For example, do this in a test script:
transform.eulerAngles = Vector3(180,0,0);
Debug.Log(transform.eulerAngles);
The output will be (0,180,180). This is not the value you expect. The change in representation would result in your cube rotating the opposite way you expect.
As for the first part of your comment, your understanding is somewhat sound.
Ah, I see. I can tell these Euler Angles are going to take some getting used to. I'm fairly new to Unity (a month or so), and you seem well versed. Is there a particular resource you might suggest looking at to boost my knowledge?
Thanks again.
Sorry I don't have a resource for you. $$anonymous$$ost of what I've learned is either through making my own mistakes or by reading about other's mistakes on this list. As a general rule, treat eulerAngles as write-only. If your object is only rotated around either 'y' or the 'z' (single axis rotation), then eulerAngles is safe to read. But not the 'x' axis. If you want to automate the 'x' axis for the first script, you could do it by using $$anonymous$$athf.Atan2() to calculate the angle, or you could compare (Vector3.Angle() or Vector3.Dot()) the transform.forward against the world forward, down, back and up axes.
Your answer
Follow this Question
Related Questions
How to get Angle float of specific axis.(Turret clamping related). 2 Answers
When applying a 90 degree rotation to Euler Angles, it is over/undershooting sometimes.. 2 Answers
new Array storing rotations 1 Answer
[OAFAT]Why does transform.rotation.x = 45 not work 3 Answers
c# modify only one axis of a quaternion 2 Answers