Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question Camera movement "jitter"

Discussion in 'Scripting' started by Rkfmckee, Jul 5, 2020.

Thread Status:
Not open for further replies.
  1. Rkfmckee

    Rkfmckee

    Joined:
    Jul 5, 2020
    Posts:
    20
    I'm making a thread for this after searching for a few days, mainly because I don't exactly know what specifically is causing the problem, I only have theories.

    I'm a unity beginner making a simple 3D game to practice, and I've been having a problem which I assume stems from a CameraController script I have. Long story short, the camera follows the player on the X and Y axis, but when it's moving it makes the health bar above the player's head very jittery and not smooth.
    I used to have the camera smoothly following the player, but this also caused the player's movement to seem kind of jittery aswell.
    All of the movement seems really smooth if the camera is stationary.

    The problem is either the camera movement, or the player and UI bar movement, but I suspect it's the camera.
    I'm trying to learn efficient ways to do this stuff, since I'm not quite used to it yet.

    Camera Controller script:
    Code (CSharp):
    1.  
    2. public class CameraController : MonoBehaviour
    3. {
    4.     public float cameraTransitionTime;
    5.  
    6.     private new Camera camera;
    7.     private Vector3 velocity;
    8.     private List<GameObject> allPlayers;
    9.     private GameObject currentPlayer;
    10.  
    11.     private float cameraDifferenceToPlayerZPosition;
    12.     private States currentState;
    13.  
    14.     #region Events
    15.  
    16.     void Start()
    17.     {
    18.         allPlayers = References.players;
    19.         camera = Camera.main;
    20.         velocity = Vector3.one;
    21.  
    22.         FindStartingPlayer();
    23.  
    24.         cameraDifferenceToPlayerZPosition = currentPlayer.transform.position.z - camera.transform.position.z;
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         Vector3 newCameraPosition = new Vector3(currentPlayer.transform.position.x, camera.transform.position.y, currentPlayer.transform.position.z - cameraDifferenceToPlayerZPosition);
    30.  
    31.         camera.transform.position = ChangePosition(newCameraPosition);
    32.     }
    33.  
    34.     #endregion
    35.  
    36.     #region Methods
    37.  
    38.     public void SetCurrentlyControlledPlayer(GameObject player) {
    39.         currentPlayer = player;
    40.         currentState = States.Transitioning;
    41.     }
    42.  
    43.     private void FindStartingPlayer() {
    44.         foreach (var currentPlayer in allPlayers) {
    45.             if (currentPlayer.GetComponent<PlayerBehaviour>().currentlyBeingControlled) {
    46.                 this.currentPlayer = currentPlayer;
    47.                 currentState = States.Following;
    48.                 return;
    49.             }
    50.         }
    51.     }
    52.  
    53.     private Vector3 ChangePosition(Vector3 newPosition) {
    54.         // Only use smooth transition if in the Transitioning state
    55.  
    56.         float distanceUntilEndTransition = 0.1f;
    57.  
    58.         float transitionTime = 0;
    59.         float xDifference = camera.transform.position.x - newPosition.x;
    60.         float zDifference = camera.transform.position.z - newPosition.z;
    61.         Vector3 differenceToNewPosition = new Vector3(xDifference, 0, zDifference);
    62.  
    63.         if (currentState == States.Transitioning) {
    64.             if (differenceToNewPosition.magnitude > distanceUntilEndTransition) {
    65.                 transitionTime = cameraTransitionTime;
    66.             } else {
    67.                 currentState = States.Following;
    68.             }
    69.         }
    70.  
    71.         return Vector3.SmoothDamp(camera.transform.position, newPosition, ref velocity, transitionTime);
    72.     }
    73.  
    74.     #endregion
    75.  
    76.     #region Enums
    77.  
    78.     public enum States {
    79.         Transitioning,
    80.         Following
    81.     }
    82.  
    83.     #endregion
    84. }
    85.  
    Player movement Script:
    Code (CSharp):
    1.  
    2. public class PlayerBehaviour : MonoBehaviour
    3. {
    4.     #region Properties
    5.  
    6.     public bool currentlyBeingControlled;
    7.     public float movementSpeed;
    8.  
    9.     private new Rigidbody rigidbody;
    10.  
    11.     private Vector3 movementAmount;
    12.     private Vector3 directionVector;
    13.  
    14.     #endregion
    15.  
    16.     #region Events
    17.  
    18.     private void Start() {
    19.         SetupInstanceVariables();
    20.     }
    21.  
    22.     private void Update() {
    23.         if (currentlyBeingControlled) {
    24.             GetMovementDirection();
    25.         } else {
    26.             directionVector = Vector3.zero;
    27.         }
    28.     }
    29.  
    30.     private void FixedUpdate() {
    31.         CalculateMovement();
    32.     }
    33.  
    34.     #endregion
    35.  
    36.     #region Methods
    37.  
    38.     private void SetupInstanceVariables() {
    39.         rigidbody = GetComponent<Rigidbody>();
    40.     }
    41.  
    42.     private void GetMovementDirection() {
    43.         var zDirection = Input.GetAxis("Vertical");
    44.         var xDirection = Input.GetAxis("Horizontal");
    45.         directionVector = new Vector3(xDirection, 0, zDirection);
    46.  
    47.         directionVector = NormaliseVectorToKeepDeceleration(directionVector);
    48.     }
    49.  
    50.     private void CalculateMovement() {
    51.         movementAmount = directionVector * (movementSpeed * Time.fixedDeltaTime);
    52.         var newPosition = transform.position + movementAmount;
    53.  
    54.         rigidbody.MovePosition(newPosition);
    55.         transform.LookAt(newPosition);
    56.     }
    57.  
    58.     private Vector3 NormaliseVectorToKeepDeceleration(Vector3 vector) {
    59.         // Normalizing a decimal vector rounds it to 1, which causes weird deceleration
    60.         // So don't do that if it's between 1 and -1
    61.  
    62.         if ((vector.magnitude > 1) || (vector.magnitude < -1)) {
    63.             vector = vector.normalized;
    64.         }
    65.  
    66.         return vector;
    67.     }
    68.  
    69.     #endregion
    70. }
    71.  
    The Health bar is moved through a different script on the player using:
    healthBar.transform.position = camera.WorldToScreenPoint(transform.position + new Vector3(0, 1, 0));
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,058
    For Rigidbody motion (or anything to do with "ganging" the camera to physics operations) you want to update the camera position inside of FixedUpdate() rather than Update(). This is because Update() calls do not map one-to-one with FixedUpdate() calls.

    If that still causes the occasional "jerk" because one script gets ahead of the other, I recommend making your own public function to update the camera, and then explicitly calling it from the movement (in the movement FixedUpdate()) call, after you have calculated your new position.

    Code (csharp):
    1. // in the player
    2.  
    3. public CameraController camControl;
    4.  
    5. // and then your code:
    6.  
    7.     private void FixedUpdate() {
    8.         CalculateMovement();
    9.         camControl.MyFixedUpdate();   // rename your Update() method in the cam controller and make it public
    10.     }
    Also, if you're curious, here is some timing diagram info:

    https://docs.unity3d.com/Manual/ExecutionOrder.html
     
    redp7a, Joe-Censored and Zer0Cool like this.
  3. Rkfmckee

    Rkfmckee

    Joined:
    Jul 5, 2020
    Posts:
    20
    Thanks for the reply!
    It was my assumption that since the camera itself doesnt have a rigidbody component and isn't a physics object that just updating it's transform should be done in regular Update, is that wrong?
     
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'm not sure I agree with this. Of course physics movement occurs in FixedUpdate, but after FixedUpdate is called you will get a call to Update before the frame is sent to the graphics card. So you can still move the camera in Update, because you will never actually see the result of movement in FixedUpdate without Update being called afterwards. Also, if you have interpolate enabled on the Rigidbody you'll have movement of the object visible in frames where FixedUpdate hasn't even been called.

    I've had best results moving the camera in LateUpdate, and then for hovering UI over characters you need to position those after the camera has moved. So you have the camera script tell the hovering UI's to reposition after the camera is done moving using an event or delegate. This is even for objects with rigidbody movement. YMMV
     
  5. Rkfmckee

    Rkfmckee

    Joined:
    Jul 5, 2020
    Posts:
    20
    Ah thanks. I've kept the camera movement in Update for now, and moved my UI movement into LateUpdate which works grand. If I ever find a need to move the camera movement into LateUpdate like you said then yeah, Ill have to look into a custom event to make sure the UI updates afterwards, but for now this is alright. Thanks a lot.
     
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,777
    This is true unless your camera has smoothed movement and the object you're following moves in FixedUpdate. If it does, then the camera could move towards the target for a few frames, then the target moves once, then the camera moves forward for a few frames - it ends up looking jittery.
     
    Joe-Censored likes this.
Thread Status:
Not open for further replies.