[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;
         }          
     }
    

    }

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.

Just in case someone would like to know how I solved my problem.

Objective

  1. Having a sphere rotating constantly at start.
  2. When a key is pressed rotation stops
  3. 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