Can not figure out how to properly change rotation during run time!

Good evening and best regards from Austria! :blush:

I’m in the process of developing a game. But I’m already failing at the rotation! My game is simply about navigating through an environment using a block (Scale: 1, 2, 1).
However, unfortunately I can’t really manage to do this, which is why I would really appreciate it if someone could help me see where my mistake lies. Unfortunately, I’m also not smart enough (which is probably where my mistake is based) to use quaternions correctly. At least it seems so. :smiling_face_with_tear:

What I have already achieved is that the “player” can be rotated in the right direction per key click. The code for this looks like this:

public Vector3 currEuler;
public Quaternion rotOutcome
void Move()
{
   rotOutcome.eulerAngles = currEuler;
   transform.rotation = rotOutcome;
  
   if (Input.GetKeyDown(KeyCode.D))
       currEuler.x += 90;
       
   if (Input.GetKeyDown(KeyCode.A))
       currEuler.x -= 90;
       
   if (Input.GetKeyDown(KeyCode.W))
       currEuler.z += 90;
  
   if (Input.GetKeyDown(KeyCode.S))
       currEuler.z -= 90;
}

As soon as the player is rotated 90° (or -90°) on the Z-axis, the rotations on the X-axis are also correct.

Now my question:
However, as soon as the player rotates on the X axis first, the rotation on the Z axis will no longer be carried out correctly. (In my case, Y and Z are the same rotation, just reversed, which rotates the player horizontally to the left or to the right)

What else struck me, I understand even less:
If I rotate the Y axis by 90° from the start, the X rotation is completed on the Z axis and vice versa. I tried the code above to adapt this method, but I had the same problem, only in this case the axes were swapped.

If anyone has a solution for me, I would be extremely grateful, as I have been trying to solve this for 2 whole working days now (around 20 hours of screen time). :pray: :pray: :pray:

PS: I know that is Spaghetti-Code but I split it up to better errogate the error. Without Success :smile:

Trying to manipulate multiple components of Euler angles can cause issues like what you’ve seen. Even experienced users can struggle with this. There’s multiple possible Euler angles to represent a single rotation. So if you change the x value of Euler angle, the y or z value could suddenly change.
Sometimes, it works out better to just rotate the object using the Transform.Rotate method rather than trying to manipulate the Euler angles in code.

You could try the following:

void Move ()
{
	if (Input.GetKeyDown (KeyCode.D)) {
			transform.Rotate (transform.InverseTransformDirection(transform.right), 90f);
		}
             
		if (Input.GetKeyDown (KeyCode.A)) {
			transform.Rotate (transform.InverseTransformDirection(transform.right), -90f);
		}
             
		if (Input.GetKeyDown (KeyCode.W)) {
			transform.Rotate (transform.InverseTransformDirection(transform.forward), 90f);
		}
        
		if (Input.GetKeyDown (KeyCode.S)) {
			transform.Rotate (transform.InverseTransformDirection(transform.forward), -90f);
		}
	}

This causes the object to rotate around the specified local axis by a certain amount.
red axis = right = x
blue axis = forward = z

The other benefit of this approach, is you can alter the parents rotation, and the code will still work.

Unfortunately, that’s not the result I need. If I rotate on the Z axis first (by pressing W or S), the following rotations on the X axis work fine.

However, if I press the X axis first ( A / D ), the following rotations on the Z axis don’t work as they should.
It should move as if you were gently nudging the cube from one side to steer it in the direction you want.

AddTorque could help here, but I can’t think of a tactic to stop the torque at a certain point.
I hope you can imagine my problem.

Thanks in advance!

Finally, I did it.

There should be a much better solution for this, but if anyone wants to test this type of character controller or is interested in the solution, feel free to copy/paste this letter jumble.

Movement also works fine with AddForce( Vector3.(direction)*5, ForceMode.VelocityChange )

I multiplied by 5 because i have a Tilemap-System for the ground. Now the character gets pushed in the desired direction perfectly tile by tile.
(Multiplied by 7.5 when the block lays because the size of 1,2,1)

Thanks a lot, I really appreciate your headache! :blush:

Here is the rubbish:

public class Controller : MonoBehaviour
{
   public Vector3 rotate;

   void Update()
   { 
        transform.localRotation = Quaternion.Euler(rotate);

        GetStartingInput();
        ResetRotation();
        RightMoveRotation();
        LeftMoveRotation();
        UpMoveRotation();
        DownMoveRotation();   
   }

    void GetStartingInput()
    {
        Vector2 input = new Vector2(Input.GetAxisRaw("Vertical"), Input.GetAxisRaw("Horizontal"));
        switch (input.x)
        {
            case < 0:
            rotate.z = -90;
            break;
            case > 0:
            rotate.z = 90;
            break;
        }
        switch (input.y)
        {
            case < 0:
            rotate.x = -90;
            break;
            case > 0:
            rotate.x = 90;
            break;
        }
    }
    void ResetRotation()
    {       // Reset the full rotation back to zero
        if ((rotate.x > 350) | (rotate.x < -350))
        rotate.x = 0;
        if ((rotate.z > 350) | (rotate.z < -350))
        rotate.z = 0;
    }
    void RightMoveRotation()
    {        // right-move-rotation handling
        if (rotate.x == 90 && rotate.z == 0)
        {
            rotate.y = 90;
            rotate.z = 90;
        }
        if (Input.GetKeyDown(KeyCode.W) && (rotate.y == 90) && (rotate.z == 90))
                rotate.x -= 90;

        if (Input.GetKeyDown(KeyCode.S) && (rotate.y == 90) && (rotate.z == 90))
                rotate.x += 90;

        if (Input.GetKeyDown(KeyCode.A) && (rotate.y == 90) && (rotate.z == 90))
                rotate = new Vector3(0,0,0);
        if (Input.GetKeyDown(KeyCode.D) && (rotate.y == 90) && (rotate.z == 90))
                rotate = new Vector3(0,0,0);
    }
    void LeftMoveRotation()
    {       // left-move-rotation handling
        if (rotate.x == -90 && rotate.y == 0 && rotate.z == 0)
        {
            rotate.y = -90;
            rotate.z = 90;
        }
        if (Input.GetKeyDown(KeyCode.W) && (rotate.y == -90) && (rotate.z == 90))
                rotate.x += 90;

        if (Input.GetKeyDown(KeyCode.S) && (rotate.y == -90) && (rotate.z == 90))
                rotate.x -= 90;

        if (Input.GetKeyDown(KeyCode.D) && (rotate.y == -90) && (rotate.z == 90))
                rotate = new Vector3(0,0,0);
        if (Input.GetKeyDown(KeyCode.A) && (rotate.y == -90) && (rotate.z == 90))
                rotate = new Vector3(0,0,0);
    }
    void UpMoveRotation()
    {       // up-move-rotation handling
        if (rotate.z == 90 && rotate.y == 0)
        {
            if (Input.GetKeyDown(KeyCode.A))
                rotate.x -= 90;

            if (Input.GetKeyDown(KeyCode.D))
                rotate.x += 90;
            
            if (Input.GetKeyDown(KeyCode.S))
                rotate = new Vector3(0,0,0);
            if (Input.GetKeyDown(KeyCode.W))
                rotate = new Vector3(0,0,0);
        }
    }
    void DownMoveRotation()
    {       // down-move-rotation handling
        if (rotate.z == -90 && rotate.y == 0)
        {
            if (Input.GetKeyDown(KeyCode.A))
                rotate.x -= 90;

            if (Input.GetKeyDown(KeyCode.D))
                rotate.x += 90;
            
            if (Input.GetKeyDown(KeyCode.S))
                rotate = new Vector3(0,0,0);
            if (Input.GetKeyDown(KeyCode.W))
                rotate = new Vector3(0,0,0);
        }
    }
}