Weird behaviors with transform.LookRotation when looking at position+Vector3

Hello! I’m working on a character controller for an isometric retro shooter. However, when making the character rotate towards where they are moving, I encountered some issues.

  • The character doesn’t fully rotate, instead of 90 degrees it’s about 85.
  • The character’s rotates sometimes lags and glitches when changing directions.

Here is my code:

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

public class PlayerMove : MonoBehaviour
{
    public float MoveSpeed;
    private CharacterController controller;
    public Quaternion lookTo;

    private Vector3 move;
    public Vector3 velocity; //For Debugging
   
    // Start is called before the first frame update
    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {
        float moveX = Input.GetAxis("Vertical")*MoveSpeed*-1f;
        float moveY = Input.GetAxis("Horizontal")*MoveSpeed;
        move = new Vector3(moveX, 0f, moveY);
        velocity = controller.velocity;
        lookTo = Quaternion.LookRotation(transform.position+controller.velocity);
        lookTo.z = 0f;
        lookTo.x = 0f;
        transform.rotation = lookTo;
      
        controller.Move(move);
    }
}

As long as lookTo is a Quaternion, the above vlues values are NOT Euler angles. They’re NOT for you to manipulate. They won’t do what you think.

Just move your player, then use LookAt() and make your player face the point you want.

Here’s more on why those fields are not what you think they are:

All about Euler angles and rotations, by StarManta:

https://starmanta.gitbooks.io/unitytipsredux/content/second-question.html

Quaternion dumper if you insist on peeking inside the ugly parts:

https://discussions.unity.com/t/920939/13

1 Like

In addition to what Kurt said, you also seem to mix up even more suff here. First of all there’s no “transform.LookRotation”, there’s a transform.LookAt method. This method actually takes a position in worldspace where the transform should look at, as well as a reference up vector to control the rotation around the look axis.

Quaternion.LookRotation on the other hand is a static method that takes a direction vector in world space as well as a reference up vector like the LookAt method of the transform component.

The LookAt method essentially just does this internally

void LookAt(Vector3 aTarget, Vector3 up)
{
    Vector3 dir = aTarget - transform.position;
    transform.rotation = Quaternion.LookRotation(dir, up);
}

However as Kurt said, you should not mess with the 4 values of a Quaternion. They are not euler angles. Rotations are represented by unit quaternions. Quaternions are a 4 dimensional number system. A unit quaternion means it always has a length of exactly 1.0. So it’s essentially a point on a 4d hypersphere. When you mess with individual components, you would denormalize it. Unity often times does normalize the quaternion (for example when assinging it to transform.rotation), however the rotation would no longer be the same.

If you want to cancel any up-down-rotation, you should zero out the y component of your direction vector. Since you don’t explicitly pass an up vector, you implicitly pass Vector3.up anyways. So the roll would be 0 as well.

        Vector3 dir = controller.velocity;
        dir.y = 0f;
        transform.rotation = Quaternion.LookRotation(dir);

Keep in mind that passing an invalid direction ( that has all zero values ) usually cause issues or errors. So be careful when doing things like that with dynamic values.

This is the answer I got from StackOverflow which explains all 3 issues with the code:
https://gamedev.stackexchange.com/a/211053/176977