Jittery Movement in 2D game with Cinemachine

Hello am looking for help with smothing out 2D movement. Am using Cinemachine for the camera system though it seems to jitter even when using a basic follow camera. I’ve notice this jitter in both my parallax background and on my player character. Not both at once however the background jitter only happens when my cininmachine brain has been set to smart update. Anyother setting also makes the player jitter. I’ve link a video showing this.

So what could be causing this?

Things I’ve tried

  • Setting the player’s rigidbody interpolate mode to interpolate
  • I’ve tried serveral parllax scripts all result in the same result
  • Using different update methods on the Cinimachine Brain and in my Parallax script

Current Code for Parllax and Movement

Player Controller

using System.Collections;
using Gameplay_Scripts;
using Gameplay_Scripts.General_Components;
using Status_Effect_System;
using UnityEngine;
using UnityEngine.InputSystem;

namespace Player_Scripts
{
    /// <summary>
    /// Handles all player movement and player input
    /// </summary>
    public class PlayerController : MonoBehaviour
    {
        [Header("Movement Settings")]
        [Tooltip("Amount of force added when the player jumps")]
        public float jumpForce = 400f;
        [Tooltip("How fast the player can run")]
        public float runSpeed = 35f;
        [Tooltip("How fast the player falls")]
        public float fallspeed = 69;
        [Tooltip("How much speed the player has in air")]
        public float inAirSpeed = 69;
        [Tooltip("How much to smooth out the movement")]
        [Range(0, .3f)] [SerializeField] private float movementSmoothing = 0.05f;
        [Tooltip("Whether or not a player can steer while jumping")]
        [SerializeField] private bool hasAirControl = false;
        [Tooltip("How fast the player accelerates")]
        [SerializeField] private float playerAcceleration = 10f;
        [SerializeField] private PlayerLegs myLegs;
       
        #region Local Vars
        private Rigidbody2D myRigidbody2D = null;
        private bool isFacingRight = true; // For determining which way the player is currently facing.
        private Health hpComp;
        private Vector3 currentVelocity = Vector3.zero;
        private float defaultRunspeed = 0f;
        #endregion

        #region Player Controls
        private PlayerControls controls = null;
        private float horizontalMove = 0f;
        #endregion

        #region Player Components
        //private Animator myAnimator = null;
        private Health healthComponent = null;
        private Rigidbody2D myRigidBody2D = null;
        #endregion

        private void Awake()
        {
            myRigidbody2D = GetComponent<Rigidbody2D>();
            hpComp = GetComponent<Health>();
            myLegs = transform.GetComponentInChildren<PlayerLegs>();
            defaultRunspeed = runSpeed;
           
            controls = new PlayerControls();

            healthComponent = GetComponent<Health>();
            myRigidBody2D = GetComponent<Rigidbody2D>();

           

            controls.Player.Jump.started += OnJumpPressed;

            controls.Player.DebugButton.started += OnDebugPress;
        }

        private void OnEnable()
        {
            controls.Player.Enable();
        }

        private void OnDisable()
        {
            controls.Player.Disable();
        }

        #region Input Actions
        /// <summary>
        /// Called when jump button is pressed
        /// </summary>
        /// <param name="context"></param>
        private void OnJumpPressed(InputAction.CallbackContext context)
        {
            if (CanPlayerMove())
            {
                Jump();
            }
        }
        /// <summary>
        /// Debug button
        /// </summary>
        /// <param name="context"></param>
        private void OnDebugPress(InputAction.CallbackContext context)
        {
            Debug.Log(PlayerState.CurrentMiteCount);
        }
        #endregion

        #region Movement Functions
        /// <summary>
        /// Check for player movement input and gun input
        /// </summary>
        private void Update()
        {
            if (CanPlayerMove())
            {
                CheckForMoveInput();
            }
        }
        /// <summary>
        /// Check for jump input if true set movement state to jumping
        /// </summary>
        private void FixedUpdate()
        {
            if (CanPlayerMove())
            {
                Move(horizontalMove * Time.fixedDeltaTime, true);
            }
        }
        /// <summary>
        /// Check to see if there is any input from the player
        /// </summary>
        private void CheckForMoveInput()
        {
            if (healthComponent.IsCurrentlyDead) return;
            horizontalMove = controls.Player.Movement.ReadValue<Vector2>().x;

            /*switch (transform.localEulerAngles.y >= 180)
                {
                    case true:
                        myAnimator.SetFloat("Speed", -horizontalMove);
                        break;
                    case false:
                        myAnimator.SetFloat("Speed", horizontalMove);
                        break;
                }*/

            if (horizontalMove == 0)
            {
                //myAnimator.SetBool("Idle", true);
            }
            else
            {
                //myAnimator.SetBool("Idle", false);
            }
        }
        /// <summary>
        /// Actually move the player based the move direction
        /// </summary>
        /// <param name="move"></param>
        /// <param name="forceFlip"></param>
        private void Move(float move,  bool forceFlip)
        {
            if (hpComp.IsCurrentlyDead) return;
            //Check to see if player is in air and applies in air speed if the player is in the air and is jumping
            if (myRigidbody2D.velocity.y < 0 || myRigidbody2D.velocity.y > 0 && !myLegs.IsGrounded)
            {
                runSpeed = inAirSpeed;
            }
            else
            {
                runSpeed = defaultRunspeed;
            }
            //only control the player if grounded or airControl is turned on
            if (!myLegs.IsGrounded && !hasAirControl) return;
            // Move the character by finding the target velocity
            var velocity = myRigidbody2D.velocity;
            Vector3 targetVelocity = new Vector2(move * runSpeed * playerAcceleration, velocity.y);
                   
            // And then smoothing it out and applying it to the character
            myRigidbody2D.velocity = Vector3.SmoothDamp(velocity, targetVelocity, ref currentVelocity, movementSmoothing);

            // If the input is moving the player right and the player is facing left...
            if (move > 0 && !isFacingRight && forceFlip)
            {
                // ... flip the player.
                // Switch the way the player is labeled as facing.
                isFacingRight = !isFacingRight;

                var transform1 = transform;
               
                var rotation = transform1.rotation;
               
                rotation = new Quaternion(rotation.x, 180f, rotation.z, 0f);
               
                transform1.rotation = rotation;

                //transform.SetPositionAndRotation();

                //GeneralFunctions.FlipObject(gameObject);
            }
            // Otherwise if the input is moving the player left and the player is facing right...
            else if (move < 0 && isFacingRight && forceFlip)
            {
                // Switch the way the player is labeled as facing.
                isFacingRight = !isFacingRight;

                var transform1 = transform;
               
                var rotation = transform1.rotation;
               
                rotation = new Quaternion(rotation.x, 0f, rotation.z, 0f);
               
                transform1.rotation = rotation;

                //GeneralFunctions.FlipObject(gameObject);
            }
        }
        /// <summary>
        /// Add Upward Velocity to make the player jump
        /// </summary>
        private void Jump()
        {
            if (!myLegs.IsGrounded) return;
           
            // Remove all force towards player
            myRigidbody2D.angularVelocity = 0f;
            myRigidbody2D.velocity = Vector2.zero;

            // Apply the actual jump force
            myRigidbody2D.AddForce(new Vector2(0f, jumpForce));
        }
        /// <summary>
        /// Called when player touches ground
        /// </summary>
        private void OnLanding()
        {
            //myAnimator.SetBool("IsJumping", false);
        }
        /// <summary>
        /// Completely stop all current movement on player will also completely freeze all incoming movement then sleeps the player rigidbody
        /// </summary>
        public void StopMovement()
        {
            myRigidbody2D.angularVelocity = 0;
            myRigidbody2D.velocity = Vector2.zero;
            currentVelocity = Vector3.zero;

            myRigidbody2D.constraints = RigidbodyConstraints2D.FreezeAll;

            myRigidbody2D.Sleep();
        }
        /// <summary>
        /// Will reset player movement and wake up the players rigidbody
        /// </summary>
        public void ResetMovement()
        {
            myRigidbody2D.WakeUp();

            myRigidbody2D.constraints = RigidbodyConstraints2D.None;

            myRigidbody2D.freezeRotation = true;
        }
        /// <summary>
        /// Checks to see if player can currently move
        /// </summary>
        /// <returns></returns>
        private bool CanPlayerMove()
        {
            return !ControlDisabled && !healthComponent.IsCurrentlyDead && !GeneralFunctions.IsConsoleOpen();
        }
        #endregion

        #region Properties
        /// <summary>
        /// Checks to see if the player is stunned
        /// </summary>
        public bool ControlDisabled { get; private set; } = false;
        /// <summary>
        /// Reference to the players box collider
        /// </summary>
        public BoxCollider2D MyBoxCollider { get; private set; } = null;
        #endregion
    }
}

Parllax Code - Used this script Parallax scrolling using orthographic camera - Questions & Answers - Unity Discussions

Parallax Camera

using UnityEngine;

namespace Map_Control_Scripts
{
    [ExecuteInEditMode]
    public class ParallaxCamera : MonoBehaviour
    {
        public delegate void ParallaxCameraDelegate(float deltaMovement);
        public ParallaxCameraDelegate ONCameraTranslate;
        private float _oldPosition;

        private void Start()
        {
            _oldPosition = transform.position.x;
        }

        public void LateUpdate()
        {
            if (transform.position.x == _oldPosition) return;

            var position = transform.position;
            var delta = _oldPosition - position.x;

            ONCameraTranslate?.Invoke(delta);
           
            _oldPosition = position.x;
        }
    }
}

Parallax Layer

using UnityEngine;

namespace Map_Control_Scripts
{
    [ExecuteInEditMode]
    public class ParallaxLayer : MonoBehaviour
    {
        public float parallaxFactor;
        public void Move(float delta)
        {
            var transform1 = transform;
            var newPos = transform1.localPosition;
            newPos.x -= delta * parallaxFactor;
            transform1.localPosition = newPos;
        }
    }
}

Parallax Background

using System.Collections.Generic;
using UnityEngine;

namespace Map_Control_Scripts
{
    [ExecuteInEditMode]
    public class ParallaxBackground : MonoBehaviour
    {
        public ParallaxCamera parallaxCamera;
        private readonly List<ParallaxLayer> _parallaxLayers = new List<ParallaxLayer>();

        private void Start()
        {
            if (parallaxCamera == null)
                if (Camera.main is { })
                    parallaxCamera = Camera.main.GetComponent<ParallaxCamera>();
            if (parallaxCamera != null)
                parallaxCamera.ONCameraTranslate += Move;
            SetLayers();
        }

        private void SetLayers()
        {
            _parallaxLayers.Clear();
            for (var i = 0; i < transform.childCount; i++)
            {
                var layer = transform.GetChild(i).GetComponent<ParallaxLayer>();

                if (layer == null) continue;

                layer.name = "Layer-" + i;
                _parallaxLayers.Add(layer);
            }
        }

        private void Move(float delta)
        {
            foreach (var layer in _parallaxLayers)
            {
                layer.Move(delta);
            }
        }
    }
}

Try putting the code from the Update funtion in your player controller script into the FixedUpdate. For me personally putting everything movement related into FixedUpdate solves the jitter.

Ya that didn’t work but thank you for the response I ended just switch from Cinemachine to Procamera 2D and that has fixed all my issues

1 Like