How to make the camera follow and face a rolling object?

I’m new to Unity, and trying to make the camera follow a rolling ball and rotate with it on the y axis so that the camera stays behind the ball and always faces in the ball’s direction of motion. This is my current script:

public class CameraMover : MonoBehaviour
{
    public Transform tf;
    public Transform ballTransform;
    public Vector3 distanceBetweenBallAndCam;
    float yRotation;

    // Start is called before the first frame update
    void Start()
    {
        distanceBetweenBallAndCam = tf.position - ballTransform.position;
    }

    // Update is called once per frame
    void Update()
    {
        tf.position = ballTransform.position + distanceBetweenBallAndCam;
        yRotation = ballTransform.eulerAngles.y;
        tf.eulerAngles = new Vector3(tf.eulerAngles.x, yRotation, tf.eulerAngles.z);
    }
}

As it is, the camera follows the ball fine, but encounters some problems on the rotation. When the ball is rolling straight down a ramp and is only rotating on the x or z axis, the camera rotates 180 degrees every half rotation of the ball. When it begins rotating on the y axis, the same problem continues to apply, with the additional issue of the camera not properly moving behind the ball. Is there a way to easily fix these problems or do I need to restart my script from scratch? Thanks in advance.

Cinemachine is a unity package that allows you to make a following camera with a smooth effect. You can find lot of videos about it and documentation here.

I don’t know exactly your project technical aspect but if you use rigid body, you can’t control the rotation of your Y-axis even with freeze it. Otherwise, you can use your velocity to know is wich direction your ball go and control your camera :

public class CameraMover : MonoBehaviour
{
    public Transform tf;
    public Transform ballTransform;
    public Rigidbody rgBall;
 
    // Start is called before the first frame update
    void Start()
    {
        rgBall = ballTransform.GetComponent<Rigidbody>();
    }
 
    // Update is called once per frame
    void Update()
    {
        // Dot product of two normalized vector is equals to cos of theire angle.
        float yRotation = -Mathf.Acos(Vector3.Dot(rgBall.velocity.normalized, Vector3.right)) * Mathf.Rad2Deg;
        tf.eulerAngles = new Vector3(0, yRotation, 0);
    }
}

To rotate around the ball I use an intermediate object with your script inside and camera in child

you can use this script:

using UnityEngine;
using System.Collections;

public class CompleteCameraController : MonoBehaviour
{

    public GameObject player;        //Public variable to store a reference to the player game object


    private Vector3 offset;            //Private variable to store the offset distance between the player and camera

    // Use this for initialization
    void Start()
    {
        //Calculate and store the offset value by getting the distance between the player's position and camera's position.
        offset = transform.position - player.transform.position;
    }

    // LateUpdate is called after Update each frame
    void LateUpdate()
    {
        // Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
        transform.position = player.transform.position + offset;
    }                                                                         
}