# Rotate an object smoothly by 90 degrees on key press in unity3D

[I saw few similar question on stackexchange but none is solving the purpose.]

I want to rotate a 3D object by 90 degrees on different axis on respective inputs. For example if 'a' is pressed, the object should rotate left by 90 degrees. transform.Rotate(0,90,0); is working but it is not rotating the object smoothly.

I am new to C# and js so cannot manually code but I tried the codes given in this answer at Rotate an object smoothly on the Y axis in Unity. The below code works but it it has two problems - code:

void Update () {
SwingOpen();
}

void SwingOpen()
{
Quaternion newRotation = Quaternion.AngleAxis(90, Vector3.up);
transform.rotation= Quaternion.Slerp(transform.rotation, newRotation, .05f);
}


Problem 1: The above code rotates object without any keyboard inputs. I added the condition if (Input.GetKeyDown (KeyCode.RightArrow)) but now the object rotates partially on every keyboard input. I want to rotate it by 90 degrees on a single key press.

Problem 2: It will never actually rotate the object by 90 deg. It will always be tending towards 90 deg. I want exact 90 deg rotation to allow multiple 90 deg rotations for 'n' number if inputs.

[EDIT]

I applied the below script but it is giving me some totally unexpected output

Code:

public float speed = 1;
private int xtimesHit = 0;
private int ytimesHit = 0;
private int ztimesHit = 0;

void Update () {
if( Input.GetKeyDown( KeyCode.RightArrow ) ){
ztimesHit--;
}
if( Input.GetKeyDown( KeyCode.LeftArrow ) ){
ztimesHit++;
}

if( Input.GetKeyDown( "a" ) ){
ytimesHit++;
}
if( Input.GetKeyDown( "d" ) ){
ytimesHit--;
}

if( Input.GetKeyDown( "w" ) ){
xtimesHit++;
}
if( Input.GetKeyDown( "s") ){
xtimesHit--;
}

this.transform.rotation = Quaternion.Lerp(this.transform.rotation, Quaternion.Euler(xtimesHit*90,ytimesHit*90,ztimesHit*90), Time.deltaTime*speed);

}


On running this script If I press rightarrow once followed by 's' the object rotates on 'z' axis and 'x' axis correctly but there after if I press arrowkeys or 'a/s' in both the cases the object rotates on y axis. I dont understand why this is happening.

I want it to rotate w.r.t. the world axis always.

This is how I would do it

private Quaternion startingRotation;
public float speed = 10;

void Start(){
//save the starting rotation
startingRotation = this.transform.rotation;
}

void Update () {
//return back to the starting rotation
if( Input.GetKeyUp( KeyCode.RightArrow ) || Input.GetKeyUp( KeyCode.LeftArrow ) ){
StopAllCoroutines();
StartCoroutine(Rotate(0));
}

//go to 90 degrees with right arrow
if( Input.GetKeyDown( KeyCode.RightArrow ) ){
StopAllCoroutines();
StartCoroutine(Rotate(90));
}

//go to -90 degrees with left arrow
if( Input.GetKeyDown( KeyCode.LeftArrow ) ){
StopAllCoroutines();
StartCoroutine(Rotate(-90));
}

}

IEnumerator Rotate(float rotationAmount){
Quaternion finalRotation = Quaternion.Euler( 0, rotationAmount, 0 ) * startingRotation;

while(this.transform.rotation != finalRotation){
this.transform.rotation = Quaternion.Lerp(this.transform.rotation, finalRotation, Time.deltaTime*speed);
yield return 0;
}
}


Edit # 1

public float speed = 1;
private int timesHit = 0;

void Update () {
if( Input.GetKeyDown( KeyCode.RightArrow ) ){
timesHit++;
}
if( Input.GetKeyDown( KeyCode.LeftArrow ) ){
timesHit--;
}

this.transform.rotation = Quaternion.Lerp(this.transform.rotation, Quaternion.Euler(0,timesHit*90,0), Time.deltaTime*speed);

}


Edit #2

Perhaps like this?

public float speed = 1;
private GameObject endRotation;

void Start(){
endRotation = new GameObject();
}

void Update () {
if( Input.GetKeyDown( KeyCode.RightArrow ) ){
endRotation.transform.Rotate(Vector3.forward, 90, Space.World);
}
if( Input.GetKeyDown( KeyCode.LeftArrow ) ){
endRotation.transform.Rotate(Vector3.forward, -90, Space.World);
}

if( Input.GetKeyDown( "a" ) ){
endRotation.transform.Rotate(Vector3.up, 90, Space.World);
}
if( Input.GetKeyDown( "d" ) ){
endRotation.transform.Rotate(Vector3.up, -90, Space.World);
}

if( Input.GetKeyDown( "w" ) ){
endRotation.transform.Rotate(Vector3.left, 90, Space.World);
}
if( Input.GetKeyDown( "s") ){
endRotation.transform.Rotate(Vector3.left, -90, Space.World);
}

this.transform.rotation = Quaternion.Lerp(this.transform.rotation, endRotation.transform.rotation, Time.deltaTime*speed);

}

• This is neither rotating smoothly not allowing multiple rotations. On first key press it rotates the objects, no actions on further key presses. – Srujan Barai Jun 1 '15 at 6:45
• You mean like this? (see Edit #1) – return true Jun 1 '15 at 6:49
• I made a mistake in previous comment, edited. – Srujan Barai Jun 1 '15 at 6:49
• Really sorry, the first code was working but i merged two script and thats why the rotation wasn't smooth. And the edit is what I was looking for. Yes! Thank you. – Srujan Barai Jun 1 '15 at 6:53
• Np, glad I could help! – return true Jun 1 '15 at 6:54

Well, the solution here is pretty simple - if you don't know how to write your own code yet, you should definitely take a course rather than looking up code and trying to patch it in your program somehow without knowing at all how it works.

First, delcare a variable called currentFrame, and initially set it to -1. Also, make a variable called numOfFrames, and set it to the number of frames over which the change will occur.

void Update () {
if(Input.GetKeyDown(KeyCode.RightArrow) && currentFrame == -1) {
currentFrame = 0;
}
if(currentFrame >= 0 && currentFrame < numOfFrames) {
SwingOpen();
currentFrame = currentFrame + 1;
}
}

void SwingOpen()
{
if (currentFrame == numOfFrames) {
Quaternion newRotation = Quaternion.AngleAxis(90, Vector3.up);
transform.rotation = newRotation;
currentFrame = -1;
}
else {
Quaternion newRotation = Quaternion.AngleAxis(90, Vector3.up);
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, .05f);
}
}


Is this what you wanted? Obviously the code could probably be made cleaner but the concept will be the same.

• You should never use frames as a counter. You always have to use time elapsed instead, because your code will run the game differently on devices which run on lower fps. – dimitris93 May 31 '15 at 18:47
• Well I suppose you could put this in Unity's FixedUpdate then... right? Well I'd say it depends if you care about smooth movement or consistent movement then. Personally sometimes I'd rather see my game run slower instead of choppily with sudden movements on slow devices. – Superdoggy May 31 '15 at 18:52
• @Shiro this is working but it still doesn't solve the second problem i mentioned. The object will always be tending towards 90 deg rotation, it will never complete. This will run like for ever. In short, this script does not allow three times 90 deg rotation if the key was pressed three times. It only allows once. – Srujan Barai Jun 1 '15 at 4:22
• @SrujanBarai Oh, I see. You don't want the object to make one rotation, but rather want it to be able to make multiple 90 degree rotations. Based off of the method name SwingOpen it sounded like you wanted to program a door that could be opened multiple times. Eh... I guess I misunderstood. – Superdoggy Jun 1 '15 at 11:24
• Oh, just noticed, returntrue's Edit #1 could be applied to my answer too. :P – Superdoggy Jun 1 '15 at 11:34