[Solved] Smooth rotation with keydown
Details:
I have a sphere that is constantly rotating in the 'y' axis, and I want to stop rotation, and go back to initial position in a smooth transition after I press 'Space'.
Problem:
When I press space the rotation stops, but there is no transition to the original position.
Code
public class Rotation : MonoBehaviour { public float X; public float Y; public float Z;
private Quaternion OriginalRotation; private Quaternion CurrentRotation; // Use this for initialization void Start() { OriginalRotation = gameObject.transform.rotation; } // Update is called once per frame void Update() { rotate(); } void rotate() { float smooth = 0.01f; if (Input.GetKeyDown(KeyCode.Space)) { print("Space bar pressed"); Y = 0; transform.rotation = Quaternion.Slerp(CurrentRotation, OriginalRotation, Time.deltaTime * smooth); //transform.rotation = OriginalRotation; } else { gameObject.transform.Rotate(X, Y, Z * Time.deltaTime); CurrentRotation = gameObject.transform.rotation; } } }
Answer by Kossuranta · Feb 01, 2017 at 10:55 AM
I can see two mistakes which are the reason why your code doesn't work. First you are using Input.GetKeyDown which will only be true during single frame, you need to use Input.GetKey instead. Then second thing is that you have Time.deltaTime in your lerp where both positions are always at the same places meaning it will only move "once" as Time.deltaTime is time between two frames. Here is really good explanation of this.
Here is code that should work. While spacebar is pressed down the object will rotate from currentRotation to originalRotation. I also changed your code a bit as generally variables should be written with small first letter and functions with capital first letter. You also created new variable smooth in your Rotate-function for no reason, so I moved it too. And you can directly call transform, no need to write gameObject.transform.
public class Rotation : MonoBehaviour
{
public float X, Y, Z;
private Quaternion originalRotation;
private Quaternion currentRotation;
private float smooth = 0.01f;
private float lerpTimer = 0;
// Use this for initialization
void Start()
{
originalRotation = transform.rotation;
}
// Update is called once per frame
void Update()
{
Rotate();
}
void Rotate()
{
if (Input.GetKey(KeyCode.Space))
{
print("Space bar pressed");
Y = 0;
lerpTimer += Time.deltaTime;
transform.rotation = Quaternion.Slerp(currentRotation, originalRotation, lerpTimer);
}
else
{
transform.Rotate(X, Y, Z * Time.deltaTime);
currentRotation = transform.rotation;
lerpTimer = 0;
}
}
}
If you want your reset rotation to work so you can only tap space and it will rotate back to original position and then continue rotating, you will need to use Coroutine.
Thank you @kossuranta for the help. I am new to C# and Unity, and to coding in general. I really appreciate the tips on C# coding conventions. I'm learning this on my own by building small projects and it is always good to have someone with more experience checking your code.
I will read about Coroutine to see how I can make my rotation to rotate back to its original position.
The smooth variable was from an old code I was trying.
Cheers
Answer by KevinKLV · Feb 02, 2017 at 12:59 AM
Just in case someone would like to know how I solved my problem.
Objective
Having a sphere rotating constantly at start.
When a key is pressed rotation stops
Sphere rotates back to its original position smoothly
Problem
Sphere was stopping but did not come back to original position. Either I needed to hold the key pressed (GetKey) or I needed to pressed several timer (GetKeyDown)
Solution
I thought that because only the rotation back would work when the input was received, what if I stop rotation only, and then check if rotation had stopped. If so, why not running another function to get the sphere back to its original position.
Code
public class Rotation : MonoBehaviour
{
//Variable for parameter avaliables in the Inspector
public float rotationSpeed;
public float returnSpeed;
//Variables declared privatly only for scrip mod
private float X, Y, Z;
private float lerpTimer = 1;
private Quaternion originalRotation;
private Quaternion currentRotation;
// Use this for initialization
void Start()
{
//Orignal Rotation value is stored in variable at start
originalRotation = transform.rotation;
}
// Update is called once per frame
void Update()
{
//Rotation function is called to continously rotate sphere
Rotate();
//checks if rotation stops and if so returns sphere to original position
if (rotationSpeed == 0)
{
RotateOrigin();
}
}
//rotate function
void Rotate()
{
//when space key is pressed rotation speed sets to zero
if (Input.GetKey(KeyCode.Space))
{
print("Space bar pressed");
rotationSpeed = 0;
}
else
{
//keeps sphere rotating continuously
Y = rotationSpeed;
transform.Rotate(X, Y, Z * Time.deltaTime);
currentRotation = transform.rotation;
lerpTimer = 0;
}
}
//Go back to orinal position function
void RotateOrigin()
{
//set lerp for smooth return to original position.
lerpTimer += Time.deltaTime;
transform.rotation = Quaternion.Slerp(currentRotation, originalRotation, lerpTimer);
}
}
This worked for me. Please feel free to comment and to criticize my solution. I tried to use a Coroutine but I could not make it work. So feel free to post a workable example if you have one.
Cheers
Here is version with coroutine. I didn't test it, but I think it should work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotation : $$anonymous$$onoBehaviour
{
public float X, Y, Z;
private Quaternion originalRotation;
private Quaternion currentRotation;
private float smooth = 0.01f;
private float lerpTimer = 0;
private WaitForEndOfFrame waitFrame = new WaitForEndOfFrame();
private bool rotating = true;
// Use this for initialization
void Start()
{
originalRotation = transform.rotation;
}
// Update is called once per frame
void Update()
{
Rotate();
}
void Rotate()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Space))
{
print("Space bar pressed");
lerpTimer = 0;
Y = 0;
rotating = false;
StartCoroutine(ResetRotation());
}
else if(rotating)
{
transform.Rotate(X, Y, Z * Time.deltaTime);
currentRotation = transform.rotation;
}
}
IEnumerator ResetRotation()
{
while(lerpTimer < 1)
{
lerpTimer += Time.deltaTime;
transform.rotation = Quaternion.Slerp(currentRotation, originalRotation, lerpTimer);
yield return waitFrame;
}
rotating = true;
}
}
Your answer
Follow this Question
Related Questions
Can't really grasp how to keep my player level on X and Z while using LookRotation 0 Answers
How to use Quaternion.Slerp with transform.LookAt? 3 Answers
unwanted rotation in y axis 0 Answers
[Solved] Quaternion from IMU sensor to GameObject Orientation problem 3 Answers
How to use Quaternion.slerp and Quaternion.LookRotation with a child gameobject 0 Answers