- Home /
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!
Answer by Rob 6 · Jul 10, 2011 at 02:33 PM
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.
Answer by Ludiares.du · Jul 09, 2011 at 11:17 AM
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.
Thanks, but that line causes it to throw an error:
"error CS1612: Cannot modify a value type return value of `UnityEngine.Transform.rotation'. Consider storing the value in a temporary variable"
What exactly are you trying to do? $$anonymous$$ake the camera face always the direction of movement?
Answer by aldonaletto · Jul 10, 2011 at 02:13 PM
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);
}
}