- Home /
Camera follow a rolling object
Hi there,
I am totally screwed. I want my camera object to follow a sphere rolling slowly downhill. The tutorial "smooth follow JS" script is not very useful, because the camera rotates with the object. But it shouldn't it should look always into the direct the sphere is rolling with a static angle. I couldn't get my C# script to do so.
Answer by Peter G · Nov 15, 2010 at 09:38 PM
Rather than having the camera offset behind the rotation of the ball. I would find the ball's velocity then use that to offset the camera. It shouldn't be too hard. Here is a proof of concept in Javascript (Sorry I would have written in in C#, but I just modded the js version for time's sake :( ) It shows a working model, but there are some opptimizations that could be done.
/* This camera smoothes out rotation around the y-axis and height for objects that roll which makes it difficult to just use the forward Vector. Horizontal Distance to the target is always fixed.
There are many different ways to smooth the rotation but doing it this way gives you a lot of control over how the camera behaves.
For every of those smoothed values we calculate the wanted value and the current value. Then we smooth it using the Lerp function. Then we apply the smoothed values to the transform's position. */
// The target we are following var target : Transform; var targetRB : Rigidbody;
// The distance in the x-z plane to the target var distance = 10.0; // the height we want the camera to be above the target var height = 5.0; // How much we var heightDamping = 2.0; var rotationDamping = 3.0;
// Place the script in the Camera-Control group in the component menu @script AddComponentMenu("Camera-Control/Smooth Follow")
function LateUpdate () { // Early out if we don't have a target if (!target || !targetRB) return;
//Take the target's velocity, remove the y and normalize it. The final step is probably unneeded but makes it easier to extend.
var direction = targetRB.velocity;
direction.y = 0;
direction = direction.normalized;
//Get the desired rotation from the ball's velocity.
var wantedRotation : Quaternion = Quaternion.LookRotation(direction);
wantedRotationAngle = wantedRotation.eulerAngles.y;
wantedHeight = target.position.y + height;
//Our current rotation is the ball's position minus our own.
var currentRotation : Quaternion = Quaternion.LookRotation(target.position - transform.position);
currentRotationAngle = currentRotation.eulerAngles.y;
currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
finalRotation = Quaternion.Euler (0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= finalRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position.y = currentHeight;
// Always look at the target
transform.LookAt (target);
}
The problem is that the JS is not portable, I had to write my own script in C#. It contains everything including the smooth follow, but I didn't implemented the right angles yet. That $$anonymous$$eans, the offset is 0. The camera looks from above onto the object. I want it to look from behind in a certain angle.
It should be perfectly portable. What part are you having trouble with? I'll help you.
Oh, is it the properties issue. In C#, you cannot set individual values in some areas such as transform.position and rotation. You have to make a new Vector3 with the current values, change the specific value such as the y, then reassign that to the property. For example. Vector3 pos = tranform.position; pos.y += height; transform.position = pos; Other than that, I don't see any issues other than changing the vars to the actual type and giving types to some of the variables declared in LateUpdate(). (I really don't like that about js that you can declare variables like that.)
I realize it's 5 years later, but here's Peter G's answer in C# - just drag your target game object onto the target field of the script. using UnityEngine; using System.Collections;
public class CameraController : $$anonymous$$onoBehaviour {
// http://answers.unity3d.com/questions/34092/camera-follow-a-rolling-object.html
// The target we are following
public Transform target;
private Rigidbody targetRB;
// The distance in the x-z plane to the target
float distance = 10.0f;
// the height we want the camera to be above the target
float height = 5.0f;
// How much we
float heightDamping = 2.0f;
float rotationDamping = 3.0f;
void Awake()
{
if (target != null)
targetRB = target.GetComponent<Rigidbody>();
}
void LateUpdate()
{
// Early out if we don't have a target
if (!target || !targetRB)
return;
//Take the target's velocity, remove the y and normalize it. The final step is probably unneeded but makes it easier to extend.
Vector3 direction = targetRB.velocity;
direction.y = 0;
direction = direction.normalized;
//Get the desired rotation from the ball's velocity.
Quaternion wantedRotation = Quaternion.LookRotation(direction);
float wantedRotationAngle = wantedRotation.eulerAngles.y;
float wantedHeight = target.position.y + height;
//Our current rotation is the ball's position $$anonymous$$us our own.
Quaternion currentRotation = Quaternion.LookRotation(target.position - transform.position);
float currentRotationAngle = currentRotation.eulerAngles.y;
float currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = $$anonymous$$athf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = $$anonymous$$athf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
Quaternion finalRotation = Quaternion.Euler(0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= finalRotation * Vector3.forward * distance;
// Set the height of the camera
Vector3 newPosition = new Vector3(transform.position.x, currentHeight, transform.position.z);
transform.position = newPosition;
// Always look at the target
transform.LookAt(target);
}
}
Thank you so much! This is exactly what I was looking for! I just had to make an account to thank you, because I've been looking for a solution to this problem for a long time now. Someone told me to use the velocity vector of the ball, but using the debug to see the velocity vector was as far as I could get on my own. Thanks again! ^.^
Your answer
Follow this Question
Related Questions
How to move camera on an angle 1 Answer
How can I limit the player's camera to move to the edge of the map centering it on the camera? 0 Answers
Get the gameobject to the left/right of current target, in field of vision? 0 Answers
calculate the angle live 0 Answers
Sliding game slope jittering. 0 Answers