Camera rotation around a single axis - following a rolling ball

I’m sure this is very simple, there’s just one line I can’t quite work out! I have an empty object at the centre of a controllable ball. The camera is a child of this empty object. This object needs to stay with the ball, and only rotate around the y axis, so that the camera swings round when you turn the ball. So far I have only managed to get as far as having the camera follow the ball with no inherited rotation whatsoever. I just can’t find a way to split the ball’s rotational Quaternion into a Vector3 and then carry that Vector3’s y value to a new Vector3 to be converted back into a Quaternion for the camera’s parent.

Here’s what I’ve got so far - this script is attached to the empty gameobject at the centre of the ball:

using UnityEngine;
using System.Collections;

public class CameraScript : MonoBehaviour 
{
    public Transform ballObject;

	void Update() 
    {
        transform.position = ballObject.transform.position;
        transform.rotation = Quaternion.Euler(0, ballObject.transform.rotation.y, 0);
	}
}

There are no compiler errors, yet it just doesn’t do anything! I’m currently getting used to C# after using JS for all my previous Unity projects, so I’m assuming there’s just something I’ve missed!

I’ve created a slightly more workable solution, merging the movement and camera scripts together. Now, the “ball centre” object that the camera is attached to controls turning, while forward and backwards controls apply a force on the ball in the direction that the camera is facing.

using UnityEngine;
using System.Collections;

public class CameraScript : MonoBehaviour 
{
    public Transform ballObject, ballCamera;
    public float speed, turnSpeed;
    Vector3 forceDirection;

	void FixedUpdate() 
    {
        transform.position = ballObject.position;
        if(Input.GetAxis("Vertical") != 0)
        {
            RollBall();
        }
        //calculate ball turning
        transform.Rotate((Vector3.up * Input.GetAxis("Horizontal") * turnSpeed), Space.World);
    }

    void RollBall()
    {
        //set force down camera's look direction
        forceDirection = ballCamera.transform.forward;

        //remove y force direction for angled camera
        forceDirection = new Vector3(forceDirection.x, 0, forceDirection.z);

        //add force to ball
        ballObject.rigidbody.AddForce(forceDirection.normalized * speed * (Input.GetAxis("Vertical")));
    }
}

The result is that the movement can be considered in a way that is independent of the rotation of the ball - so it’s more of a work-around than a solution, but there didn’t seem to be a graceful way to clone a rotation value across via a Vector3.

Try this:

using UnityEngine;
using System.Collections;

public class CameraScript : MonoBehaviour
{
public Transform ballObject;

void Update() 
{
    transform.position = ballObject.position;
    transform.rotation.eulerAngles = new Vector3(0, ballObject.transform.rotation.y, 0);
}

}

You don’t need to add the .transform after ballObject because it is a transform.

If what you want is just to keep the camera facing always the direction of movement, you must calculate its direction based on the last position. To avoid inaccuracies produced by very small displacements, you can set a minimum distance to refresh the view direction (adjust the distance variable in the Inspector if needed):

using UnityEngine;
using System.Collections;

public class CameraScript : MonoBehaviour 
{
    public Transform ballObject;    
	public float distance = 0.1f; // min distance to refresh view direction

	Vector3 lastPos;
	Vector3 viewDir;
	
	void Start(){
        // ensure forward direction at start
		lastPos = ballObject.transform.position - transform.forward * distance; 
	}		
	
    void Update() 
    {
		Vector3 ballPos = ballObject.transform.position;
		Vector3 newDir = ballPos - lastPos;  // direction from last position
		newDir.y = 0;	// keep the camera on horizontal plane
		if (newDir.magnitude>distance){  // only recalculate after min distance
			viewDir = newDir;
			lastPos = ballPos;
		}
        transform.position = ballPos;
		transform.forward = Vector3.Slerp(transform.forward, viewDir.normalized, Time.deltaTime);
    }
}