0

I have an aeroplane controller that can rotate on z and y axes. When the up/down or left/right inputs == 0, I want the plane rotation to reset (become level again).

After some trial and error, this works:

if (Input.GetAxis("Horizontal") == 0.0f && transform.rotation.z != 0f) {
  Vector3 tempRotation = new Vector3();
  tempRotation.z = 0.0f;
  transform.rotation = Quaternion.Euler(tempRotation);
}

However, this immediately snaps into position. I want it to be a gradual rotation. This also affects the camera in a negative way (also snaps).

I tried stuff like tempRotation.z -= 0.1f; for each update cycle etc, but this doesn't stop when it gets to 0 (and I have no idea why):

if (Input.GetAxis("Horizontal") == 0.0f && transform.rotation.z != 0.0f) {
  Vector3 tempRotation = transform.rotation.eulerAngles;
  tempRotation.z = (float) Math.Round(tempRot.z, 1);
  tempRotation.z += 0.1f;
  transform.rotation = Quaternion.Euler(tempRotation);
}

Does anyone have any idea? Thank you.

Joseph
  • 691
  • 4
  • 18

1 Answers1

1

First, don't use transform.rotation.z unless you know Quaternions inside and out. You probably meant to use transform.eulerAngles.z.

You can check the y component of local right to determine if it is tilted, and use Quaternion.LookRotation to find the "resetted" rotation, this is a bit safer than using eulerAngles.

Then, you have to make the rotation. For a very simple constant speed you could use Quaternion.RotateTowards to rotate towards it:

[SerializeField] float resetSpeed;

// ...

if (Input.GetAxis("Horizontal") == 0.0f && !Mathf.Approximately(transform.right.y, 0f))
{
    Quaternion startRot = transform.rotation;
    Quaternion goalRot = Quaternion.LookRotation(transform.forward);
    transform.rotation = Quaternion.RotateTowards(startRot, goalRot, 
            resetSpeed * Time.deltaTime);
}

if (Input.GetAxis("Vertical") == 0.0f && !Mathf.Approximately(transform.forward.y, 0f))
{
    Quaternion startRot = transform.rotation;
    Quaternion goalRot = Quaternion.LookRotation(Vector3.Scale(transform.forward,
            Vector3(1f,0f,1f)), transform.up);
    transform.rotation = Quaternion.RotateTowards(startRot, goalRot, 
            resetSpeed * Time.deltaTime);
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • This is perfect @Ruzihm, thank you very much! – Joseph Dec 09 '21 at 17:45
  • I'm now trying to get this to work for up/down rotation too, any idea why this doesn't work? And to combine, would I just add `transform.up` and `transform.forward` in `LookRotation`? ```cs if (Input.GetAxis("Vertical") == 0.0f && !Mathf.Approximately(transform.up.z, 0f)) { Quaternion startRot = transform.rotation; Quaternion goalRot = Quaternion.LookRotation(transform.up); transform.rotation = Quaternion.RotateTowards(startRot, goalRot, resetSpeed * Time.deltaTime); } ``` – Joseph Dec 09 '21 at 18:27
  • 1
    I would do the same thing in a separate `if` for `"Vertical"`. only with `goalRot = Quaternion.LookRotation(Vector3.Scale(new Vector3(1f,0f,1f), transform.forward), transform.up);` and you can check `!Mathf.Approximately(transform.forward.y, 0f)` – Ruzihm Dec 09 '21 at 18:29
  • Fantastic, thank you so much. I was a little confused looking at the Unity documentation — where it refers to colours, they are different depending on whether referring to the scene, or the object. I really appreciate your help! – Joseph Dec 09 '21 at 18:37