Cube Rotation Using Quaternion

Hi,

I have the following snippet of code, and amongst other things, it rotates a cube using Euler angles (180 degrees in the chosen direction), visually it seems to work.

Now, if I place a visual test on the cube, for instance, a smaller cube without a box collider on top, it still works, flips 180, but then the cube is always upside down, meaning it never fully flips back up (180), even though it goes through the rotation animation again, I’m just testing ‘right’ movement for now, but all other directions do the same thing ?

Any ideas or suggestions on how to rotate ‘back’ again, if I’m ‘already’ rotated ? Thanks.

    IEnumerator CubeMovement(MoveDirection moveDirection, float duration)
    {
        canMove = false;
        float progress = 0f;

        Quaternion endRotation = Quaternion.Euler(0, 0, 0);
        Vector3 targetPosition = new Vector3(currentCubePosition.x + Distance, currentCubePosition.y, currentCubePosition.z);

        if (moveDirection == MoveDirection.UP)
        {
            endRotation = Quaternion.Euler(-180, 0, 0);
            targetPosition = new Vector3(currentCubePosition.x, currentCubePosition.y, currentCubePosition.z + Distance);
        }

        else if (moveDirection == MoveDirection.DOWN)
        {
            endRotation = Quaternion.Euler(180, 0, 0);
            targetPosition = new Vector3(currentCubePosition.x, currentCubePosition.y, currentCubePosition.z - Distance);
        }

        else if (moveDirection == MoveDirection.LEFT)
        {
            endRotation = Quaternion.Euler(0, 0, -180);
            targetPosition = new Vector3(currentCubePosition.x - Distance, currentCubePosition.y, currentCubePosition.z);
        }

        else if (moveDirection == MoveDirection.RIGHT)
        {
            endRotation = Quaternion.Euler(0, 0, 180);
            targetPosition = new Vector3(currentCubePosition.x + Distance, currentCubePosition.y, currentCubePosition.z);
        }

        Vector3 endPosition = new Vector3(targetPosition.x, currentCubePosition.y, targetPosition.z);

        while (progress < duration)
        {
            progress += Time.deltaTime;

            float percent = Mathf.Clamp01(progress / duration);
            float height = jumpHeight * Mathf.Sin(Mathf.PI * percent);

            transform.position = Vector3.Lerp(currentCubePosition, endPosition, percent) + new Vector3(0, height, 0);
            transform.rotation = Quaternion.Lerp(currentCubeRotation, endRotation, percent);

            yield return null;
        }

        currentCubePosition = new Vector3(transform.position.x, 0.5f, transform.position.z);
        canMove = true;
    }
}

You don’t seem to set currentCubeRotation after the while loop like you do the position?

1 Like

I’m not sure I can picture what the issue is, unfortunately. Can you provide some diagrams, a gif or something?

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

public class GridHopRotation : MonoBehaviour
{
   public enum MoveDirection
   {
       RIGHT,
       LEFT,
       UP,
       DOWN
   }

   private bool canMove;
   private Vector3 currentCubePosition;
   private int currentCubePitch;
   private int currentCubeRoll;


   public float Distance;
   public float jumpHeight;
   public float Duration;

   void Start()
   {
       canMove = true;
       currentCubePosition = transform.position;

       // This isn't the most reliable, ideally have your cube always at 0,0,0 rotation at the start
       currentCubePitch = (int)transform.rotation.eulerAngles.x;
       currentCubeRoll = (int)transform.rotation.eulerAngles.z;
   }

   void Update()
   {
       if (canMove)
       {
           if (Input.GetKeyDown(KeyCode.UpArrow))
               StartCoroutine(CubeMovement(MoveDirection.UP, Duration));

           else if (Input.GetKeyDown(KeyCode.DownArrow))
               StartCoroutine(CubeMovement(MoveDirection.DOWN, Duration));

           else if (Input.GetKeyDown(KeyCode.LeftArrow))
               StartCoroutine(CubeMovement(MoveDirection.LEFT, Duration));

           else if (Input.GetKeyDown(KeyCode.RightArrow))
               StartCoroutine(CubeMovement(MoveDirection.RIGHT, Duration));
       }
   }

   IEnumerator CubeMovement(MoveDirection moveDirection, float duration)
   {
       canMove = false;
       float progress = 0f;

       Vector3 targetPosition = new Vector3(currentCubePosition.x + Distance, currentCubePosition.y, currentCubePosition.z);

       int targetPitch = 0;
       int targetRoll = 0;

       if (moveDirection == MoveDirection.UP)
       {
           targetPitch += 180;
           targetPosition = new Vector3(currentCubePosition.x, currentCubePosition.y, currentCubePosition.z + Distance);
       }

       else if (moveDirection == MoveDirection.DOWN)
       {
           targetPitch -= 180;
           targetPosition = new Vector3(currentCubePosition.x, currentCubePosition.y, currentCubePosition.z - Distance);
       }

       else if (moveDirection == MoveDirection.LEFT)
       {
           targetRoll += 180;
           targetPosition = new Vector3(currentCubePosition.x - Distance, currentCubePosition.y, currentCubePosition.z);
       }

       else if (moveDirection == MoveDirection.RIGHT)
       {
           targetRoll -= 180;
           targetPosition = new Vector3(currentCubePosition.x + Distance, currentCubePosition.y, currentCubePosition.z);
       }

       Vector3 endPosition = new Vector3(targetPosition.x, currentCubePosition.y, targetPosition.z);
       Vector3 endRotation = new Vector3(targetPitch, 0f, targetRoll);

       while (progress < duration)
       {
           progress += Time.deltaTime;

           float percent = Mathf.Clamp01(progress / duration);
           float height = jumpHeight * Mathf.Sin(Mathf.PI * percent);

           transform.position = Vector3.Lerp(currentCubePosition, endPosition, percent) + new Vector3(0, height, 0);
           transform.Rotate((endRotation / duration) * Time.deltaTime, Space.World);

           yield return null;
       }

       currentCubePosition = new Vector3(transform.position.x, 0.5f, transform.position.z);
       currentCubePitch += targetPitch;
       currentCubeRoll += targetRoll;

       transform.rotation = Quaternion.Euler(currentCubePitch, 0f, currentCubeRoll);

       canMove = true;
   }
}

This is working from what I can tell. I got rid of the lerp on the rotation because it’s ambiguous (+180 degrees can go either “left” or “right” as they’re both the shortest distance), and stored the angles separately to rebuild the rotation after the coroutine to the “proper” values.

Let me know if you have any issues.

1 Like