Problem Rotating Cube

So i want to be able to rotate the cube in 2 directions when i press key up down or left right
the cube need to be able to rotate like the brown arrow (1 and 2) but never like the red one (3)

here is my code so far :

 public float smooth = 1f;
    private Quaternion targetRotation;
    // Start is called before the first frame update
    void Start()
    {
        targetRotation = transform.rotation;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown("right"))
        {
            StopAllCoroutines();
            targetRotation *= Quaternion.AngleAxis(90, Vector3.right);
            StartCoroutine(RotateX(targetRotation));
        }

        if (Input.GetKeyDown("left"))
        {
            StopAllCoroutines();
            targetRotation *= Quaternion.AngleAxis(90, Vector3.left);
            StartCoroutine(RotateX(targetRotation));
        }

        if (Input.GetKeyDown("up"))
        {
            StopAllCoroutines();
            targetRotation *= Quaternion.AngleAxis(90, Vector3.up);
            StartCoroutine(RotateX(targetRotation));
        }

        if (Input.GetKeyDown("down"))
        {
        
                      
            StopAllCoroutines();
            targetRotation *= Quaternion.AngleAxis(90, Vector3.down);
            StartCoroutine(RotateX(targetRotation));
        }
       
       

        IEnumerator RotateX(Quaternion targetRotation)
        {
            while (transform.rotation != targetRotation)
            {
                transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 10 * smooth * Time.deltaTime);
                yield return null;
            }
        }


    }

this code works well but the cubes rotates in all direction and i dont know how to "lock it’ to only rotate on 2 axis.

sorry for my english, it-s not my mothertongue.

thank you in advance for your help and have a good day everyone

Hi,
You are rotating the object that you are using as an axis system, so subsequent rotations are not in the directions you expected. The following seems very ugly and perhaps a better coder than me can fix that, but it does appear to work:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cube : MonoBehaviour
{
    public float smooth = 50f;
    private bool ready = true;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.RightArrow) && ready) StartCoroutine(RotateX(new Vector3(1, 0, 0), 90));
        if (Input.GetKeyDown(KeyCode.LeftArrow) && ready) StartCoroutine(RotateX(new Vector3(1, 0, 0), -90));
        if (Input.GetKeyDown(KeyCode.UpArrow) && ready) StartCoroutine(RotateX(new Vector3(0, 0, 1), 90));
        if (Input.GetKeyDown(KeyCode.DownArrow) && ready) StartCoroutine(RotateX(new Vector3(0, 0, 1), -90));

        IEnumerator RotateX(Vector3 axis, float angle)
        {
            ready = false;
            float timestep = smooth * Time.deltaTime;
            float currentAngle = 0;
            int sign = (int)Mathf.Sign(angle);

            while (true)
            {
                currentAngle += timestep;
                transform.RotateAround(transform.position, axis, timestep * sign);
                if (currentAngle >= 90) break;
                yield return null;
            }

            ready = true;
        }
    }
}

I tried to keep your variable names, but I changed the input slightly so that it does not need any external setup, feel free to change it back to Input.GetKeyDown(“down”) etc.

Using RotateAround gets you out of the trap of re-orienting the coordinate system that you are using to rotate about.

The horrible bool “ready” prevents rotations getting mixed up together and producing a mess.

Because of the line “if (currentAngle >= 90) break;” there is likely to be a very small amount of drift over a large number of rotations due to rounding error, but I could not figure an easy way to bring a lerp into the rotate around - once again, perhaps someone else has a better method.

Anyway, it’s a start, hope it helps.

Edit:
Slight tidy of code…

1 Like

I tend to have 2 objects, one rotating on the Y and one rotating on the X, mainly used on a pivot camera.

Yes I thought about that, but wondered if it was possible with a single object… Also doing the rotate with world.space seems an option, but I could not get that to work.

Thanks guys, i tried your code and it works but after a few rotation the cube start to be completely offset so i will try to dig a bit more and find a way to wait for the rotation to be complete before starting a new one.

i tought about using 2 object but after playing with a dice for a while i did not figure any way to make it work because the 2 potential object will ‘overlapse’

will let you know if i find a solution thanks again for your help

you can either lose some flexibility on rotation speed by moving to ints:

        IEnumerator RotateX(Vector3 axis, float angle)
        {
            ready = false;
            int timestep = 1;
            int currentAngle = 0;
            int sign = (int)Mathf.Sign(angle);

            while (true)
            {
                currentAngle += timestep;
                transform.RotateAround(transform.position, axis, timestep * sign);
                if (currentAngle >= 90) break;
                yield return null;
            }

            ready = true;
        }

or add some extra code to make sure after the final step of the loop you force it back to the exact 90 degree rotation.

You could also use floats that round to the 90 (e.g. 1.5f), accepting the extremely small precision errors that would bring - you don’t say how many times you expect to rotate the cube.