Rotation Innaccuracy

New to this so please bear with me if there’s an obvious answer to this. I’ve set up a script that rotates the camera 90 degrees left/right on a button press and it works except that there’s a build of %error everytime I press a key. Eventually it ends up rotating in multiples of ~30 degrees. I understand that this is down to converting from Euler to Quaternion to Euler, but what I’ve not managed to find on the forums is how do I write the whole script using Quaternions?

    IEnumerator RotateMe(Vector3 ang, float time)
    {
        var sAngle = transform.rotation;
        var eAngle = Quaternion.Euler(transform.eulerAngles + ang);
        for (var t = 0f; t < 1; t += Time.deltaTime / time)
        {
            transform.rotation = Quaternion.Lerp(sAngle, eAngle, t);
            yield return null;
        }
    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown("left"))
        {
            StartCoroutine(RotateMe(Vector3.up * 90, 0.5f));
        }
        if (Input.GetKeyDown("right"))
        {
            StartCoroutine(RotateMe(Vector3.up * -90, 0.5f));
        }
    }

Quaternions are a tough mathematical topic so I recommend to get rid of Quaternions and Eulers conversions and use built in methods:

Coroutine coroutine = null;
bool canRunCoroutine = true;

IEnumerator RotateMe(Vector3 angle, float time)
{
	float timer = 0f;
	Quaternion rotation = transform.rotation;
	canRunCoroutine = false;

	while(timer < time)
	{
		transform.Rotate(angle * Time.deltaTime / time, Space.Self); //can also be Space.World to rotate it in world space instead of local space
		timer += Time.deltaTime;
		yield return new WaitForEndOfFrame();
	}

	transform.rotation = rotation;
	transform.Rotate(angle, Space.Self); //set rotation by hand, exactly like it's supposed to be

	canRunCoroutine = true;
}

void Update()
{
	if(Input.GetKeyDown("left") && canRunCoroutine) //canRunCouroutine to make sure you will not get other angles than 0, 90, 180 and 270.
	{
		StartCoroutine(RotateMe(Vector3.up * 90, 0.5f));
	}
	if(Input.GetKeyDown("right") && canRunCoroutine)
	{
		StartCoroutine(RotateMe(Vector3.up * -90, 0.5f));
	}
}

Perhaps use GetKey instead of GetKeyDown for smooth rotations while holding down the key.

Kind regards,

Yorick

I’m very far from a pro, very far!

As I understand, it ends up rotating by 30°, but at the begining, the rotation is almost correct no? If I understand correctly:

My solution would be to store your Y rotation as an Integer variable (ie: yRot). Each time you rotate from key press you could add +/-90 to that int. When you reach 360, yRot = 0. if you reach -90, yRot = 270

and you could then do (not tested, am at work):

     IEnumerator RotateMe(float time)
     {
         var sAngle = transform.rotation;
         var eAngle = tranform.rotation;
         eAngle.y = yRot;
         
         for (var t = 0f; t < 1; t += Time.deltaTime / time)
         {
             transform.rotation = Quaternion.Lerp(sAngle, eAngle, t);
             yield return null;
         }
     }

Your update would then become:

void Update () {
         bool changed = false;
         if (Input.GetKeyDown("left"))
         {
             changed = true;
             yRot += 90;
         }
         if (Input.GetKeyDown("right"))
         {
             changed = true;
             yRot -= 90;
         }
         if (changed)
         {
             if (yRot == 360) {yRot = 0;}
             elseif (yRot == -90) {yRot = 270;}
             StartCoroutine(RotateMe(0.5f));
         }
     }

FYI: transform.rotation is already a Quaternion.