1
votes

So far learning unity, camera rotation with mouse is the thing that has given me the most problems. Now the problem I am facing is, when making a first person controller based on rigidbody, that the rotation of the character and camera with the mouse is inconsistent and jittery.

This youtube video, shows the problem. In it, i am smoothly moving the mouse but the rotation seems to sometimes skip some intermediate rotations and jump to new values.

This is the hierarchy I am currently using for the character as well as the attached components: Image showing the hierarchy and attached components of a rigidbody based character

And this is the complete code for the script

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

    [RequireComponent(typeof(Rigidbody), typeof(Collider))]
    public class CompleteRBController : MonoBehaviour
    {
    [Header("Referenced components:")]
    [SerializeField]
    private Rigidbody _rb;
    [SerializeField]
    private Transform _cameraTransform;


    [Header("Mouse Settings")]
    public float _mouseSensitivity = 100f;
    [SerializeField]
    private float pitch = 0f;
    [SerializeField]
    private bool _mouseInverted = false;


    [Header("Parameters:")]
    [SerializeField]
    private float _speed = 10f;
    [SerializeField]
    private float _sprintSpeed = 15f;
    // Start is called before the first frame update
    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
    }

    // Update is called once per frame
    void Update()
    {

    }

    private void FixedUpdate()
    {
        //Get input mouse
        float mouseX = Input.GetAxisRaw("Mouse X") * _mouseSensitivity * Time.fixedDeltaTime;
        float mouseY = Input.GetAxisRaw("Mouse Y") * _mouseSensitivity * Time.fixedDeltaTime;

        //Get input keyboard
        float vertical = Input.GetAxisRaw("Vertical");
        float horizontal = Input.GetAxisRaw("Horizontal");

        // Debug.Log(string.Format("Vertical: {0}, Horizontal: {1}", vertical, horizontal));

        bool isSprinting = Input.GetKey(KeyCode.LeftShift);

        //Rotate
        pitch += (_mouseInverted) ? -mouseY : mouseY;
        pitch = Mathf.Clamp(pitch, -89, 89);

        _cameraTransform.localRotation = Quaternion.Euler(pitch, 0, 0);
        transform.Rotate(transform.up * mouseX);

        //Move
        Vector3 move = (transform.forward * vertical + transform.right * horizontal).normalized * ((isSprinting)? _sprintSpeed : _speed);
        _rb.velocity = new Vector3(move.x, _rb.velocity.y, move.z);
    }

}

I will also add a list of things I tried to change to make it smooth:

  • Changing getAxisRaw with getAxis. No effect on the smoothness of the camera movement.
  • Lerping the vertical rotation. Adds too much delay, does not really seem suitable for FPS controller? How would I lerp the yaw?
  • Move the rotation from FixedUpdate to Update. Does not do anything, and we are editing a rigidbody so it would be still better to do it on fixedUpdate with all other physic related calculations.
  • Make separate components one for the rotation and the other for the movement. does not help either.

Sometimes on the first seconds of the simulation i does work smoothly but after a little while it becomes wonky again.

I dont really know how to fix it / what is causing the problem. I would really appreciate it if you could help me with this or put me in the right track to understanding the problem.

Thanks in advance for helping me.

1
Try putting the camera movement in LateUpdate(). I am not sure the results with your given code as I do not know how the entire project is setup, but this might help. The other thing is all input code should be in Update() not FixedUpdate(). Only use physics calculations for FixedUpdate(). I would store your input as variables in Update(), update your movement in FixedUpdate() and update the camera in LateUpdate(). - TEEBQNE
@TEEBQNE thanks for the advice! it really lowered the jittery effect and added a better order for the script execution, thanks! - Javari

1 Answers

1
votes

The skipping occurs whenever the FixedUpdate does not match the updating of a frame / Update(). Thats why you should put all Input related stuff in Update and all Physics related stuff in FixedUpdate. I would recommend you to make a Inputmanager Method and a CalculateMovement method. Then put the Inputmanager Method in Update and the CalculateMovement method in FixedUpdate. Also Time.fixedDeltaTime is not the same as Time.DeltaTime. If you put the Input in Update instead of FixedUpdate, you have to change it to Time.DeltaTime instead. Hope i could help you! :)