Unity Camera Follow and Rigidbody2D

Please help! I’m not sure what else to do… I’ve spent all day trying to make this work. I tried Cinemachine as well but the behaviour is identical.

I’m building a 2D platformer game, where the player jumps up towards platforms and then lands on them.
My platforms have a Box Collider 2D and my character has a Rigidbody2D with Gravity Scale set to 7 and a box collider 2D as well.

Everything is working well, including the jumping mechanic, but starts breaking when I try to implement a camera to follow the player movement.

Below is my simple code which I attach to the camera and then I drag the player game object to the Target field. When I press play, the object falls down to a Y position of -896, where it collides with a platform and the console logs “isGrounded: True”, however if I check the Main Camera position, the Y value keeps going infinitely beyond -896 and the Z axis keeps going up to very high positive numbers (e.g 200k) (this is a 2D game with no Z axis movement).

In scene view, the Canvas/Main Camera keep falling down. If I set the RigidBody2D gravity scale to zero the camera stops falling, but so does the player game object.

using UnityEngine;

public class CameraFollow : MonoBehaviour
{
    public Transform target; // The object the camera will follow
    public Vector3 offset = new Vector3(0, 0, -10); // Offset to keep the camera at a distance
    public float smoothSpeed = 0.125f; // Speed of the camera's smooth movement

    void LateUpdate()
    {
        if (target != null)
        {
            // Calculate desired position based on the target's position and the offset
            Vector3 desiredPosition = target.position + offset;

            // Smoothly move to the desired position
            Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);

            // Apply the smoothed position
            transform.position = smoothedPosition;
        }
    }
}

Pasting my playermovement script below as well in case this helps with the deep dive:

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float maxJumpForce = 100f;
    public float joystickRadius = 20f; // Radius to detect click/touch area around the frog
    public float dragThresholdX = 0.5f; // Threshold for determining left, right, or center drag
    public Animator animator;

    private Vector2 dragStartPosition;
    private bool isDragging = false;
    private Rigidbody2D rb;

    // Ground check variables
    public LayerMask groundLayer;
    public Transform groundCheck;
    public float groundCheckRadius = 0.1f;
    private bool isGrounded;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        // Detect touch/click near the frog
        if (Input.GetMouseButtonDown(0))
        {
            Vector2 touchPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            touchPosition = new Vector2(touchPosition.x, touchPosition.y); // Ignore Z-axis

            Vector2 frogPosition = new Vector2(transform.position.x, transform.position.y); // Ignore Z-axis

            float distance = Vector2.Distance(touchPosition, frogPosition);

            Debug.Log("Touch position: " + touchPosition + ", Frog position: " + frogPosition);
            Debug.Log("Distance: " + distance + ", Joystick radius: " + joystickRadius);

            if (distance <= joystickRadius)
            {
                isDragging = true;
                dragStartPosition = touchPosition;
                animator.SetBool("isDragging", true);
                Debug.Log("Drag started at: " + dragStartPosition);
            }
            else
            {
                Debug.Log("Touch is outside of joystick radius");
            }
        }

        // Handle dragging and set animations (stay in Update for responsiveness)
        if (Input.GetMouseButton(0) && isDragging)
        {
            Vector2 currentDragPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            currentDragPosition = new Vector2(currentDragPosition.x, currentDragPosition.y);  // Ignore Z-axis

            // Log the current drag position whenever it changes
            Debug.Log("Current Drag Position: " + currentDragPosition);

            Vector2 dragVector = currentDragPosition - dragStartPosition;

            // Drag direction based on X-offset
            if (Mathf.Abs(dragVector.x) < dragThresholdX) // Drag near center
            {
                animator.SetFloat("dragDirection", 0); // Center drag animation
            }
            else if (dragVector.x < -dragThresholdX) // Drag left
            {
                animator.SetFloat("dragDirection", -1); // Drag left animation for jump up-left
            }
            else if (dragVector.x > dragThresholdX) // Drag right
            {
                animator.SetFloat("dragDirection", 1); // Drag right animation for jump up-right
            }
        }

        // Release and jump (this remains in Update to handle input)
        if (Input.GetMouseButtonUp(0) && isDragging && isGrounded)
        {
            Vector2 releasePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            releasePosition = new Vector2(releasePosition.x, releasePosition.y);  // Ignore Z-axis

            // Calculate drag vector from release position and initial drag start position
            Vector2 dragVector = releasePosition - dragStartPosition;

            Debug.Log("Release Position: " + releasePosition);
            Debug.Log("Drag Vector: " + dragVector);

            // Calculate jump force based on drag distance
            float jumpForce = Mathf.Clamp(dragVector.magnitude, 0, maxJumpForce);

            // Apply multiplier to add more power to the jump (e.g., 1.5x the calculated force)
            jumpForce *= 5.0f;  // This multiplier increases the jump force

            // Log the jump force
            Debug.Log("Jump Force: " + jumpForce);

            // Check if jump force is valid
            if (jumpForce > 0)
            {
                // Log jump direction and force
                Vector2 jumpDirection = -dragVector.normalized;
                Debug.Log("Jump direction: " + jumpDirection + ", Jump force: " + jumpForce);

                // Apply jump force
                rb.AddForce(jumpDirection * jumpForce, ForceMode2D.Impulse);
                
                // Update jump direction animations
                if (jumpDirection.x > 0) // Jump up-right
                {
                    animator.SetFloat("jumpDirection", 1);
                }
                else if (jumpDirection.x < 0) // Jump up-left
                {
                    animator.SetFloat("jumpDirection", -1);
                }
                else // Jump straight up
                {
                    animator.SetFloat("jumpDirection", 0);
                }

                // Reset drag state and animations
                isDragging = false;
                animator.SetBool("isDragging", false);
            }
            else
            {
                // If the drag vector is too small, log a message
                Debug.Log("Jump force too low or invalid.");
            }
        }
    }

    void FixedUpdate()
    {
        // Ground check in FixedUpdate
        isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);

        // Update grounded animation state only when it changes
        if (isGrounded != animator.GetBool("isGrounded"))
        {
            Debug.Log("Grounded state changed: " + isGrounded);
            animator.SetBool("isGrounded", isGrounded);
        }

        // Optionally: Handle horizontal movement here (if needed for further adjustments)
        // Example: rb.velocity = new Vector2(horizontalVelocity, rb.velocity.y);
    }

    void OnDrawGizmos()
    {
        // Visualize ground check radius
        if (groundCheck != null)
        {
            Gizmos.color = Color.red;
            Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius);
        }
    }
}

What happens if you remove the smoothing code and just do transform.position = desiredPosition?

Even with the smoothing removed, when I click Play, within a few seconds the Y transform value of the Main Camera reaches -10k and the Z transform value +100k and both keep going infinitely even after my rigid body has collided with the platform and is static.

Are you sure that your camera is tracking the correct object?

Yes of course. I discovered that when I change the Canvas render mode from Screen Space Camera to Screen Space Overlay, the camera stops falling infinitely, however this is giving me a series of other issues like sprite renderers appearing behind the background image etc… not sure how to solve this

I have no idea what you’re doing. How is a canvas involved in this? Perhaps you should give more context.