- Home /
Problem in rotating camera around a moving player
Ok so my Camera script is pretty simple. What the LateUpdate simply does is to keep an offset (defined on inspector) between the Camera and the Player while smoothing out the translation. This works perfectly. What i'm trying to do now is to rotate the Camera when the user wishes to (using an horizontal Joystick, the cameraJoystick) and to do so i added that code on Update. It is working, the problem with this however is that everytime i move the player away from the Camera and rotate the Camera, the Camera slowly gets aways from the Player. On the other hand, if i move the player in the direction the Camera is facing, then the Camera will slowly zoom onto the player until it gets right above the player and looking down on it. How can i fix this zoom IN/OUT behaviour?
public class CameraFollow : MonoBehaviour
{
//for camera follow
public Transform target;
public float smoothSpeed = 0.125f;
public Vector3 offset;
//for camera rotation
public float speed = 1.5f;
public Joystick cameraJoystick;
void Update(){
if (cameraJoystick.Horizontal != 0)
{
transform.RotateAround(target.position, Vector3.up, -cameraJoystick.Horizontal * speed);
offset = transform.position - target.position;
}
}
void LateUpdate()
{
follow();
}
void follow() {
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
transform.LookAt(target);
}
}
Answer by Scribe · Apr 12, 2020 at 10:51 PM
The issue will like come from this code:
offset = transform.position - target.position;
You will likely get small increase and decreases in the length of offset, because transform.position
is not the same value as desiredPosition
, it is somewhere inbetween as you interpolate towards desiredPosition
.
Those small errors will add up over time causing the effect you see.
One solution would be to introduce another float variable, called for example followDistance
. Then the calculation of offset should become:
offset = followDistance * (transform.position - target.position).normalized;
This has the added bonus that you can introduce zooming in and out easily if you want by just increasing/decreasing the value of followDistance
.
EDIT
I guess even with the changes above we are still going to accumulate errors over time as we change the value of offset at each step. Below is some code that should solve the issue, the important bit to notice is that the value of offset is never changed, so we know that when we work out the rotation it will always we some rotation of the original offset value around the up vector, which is what you want!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
//for camera follow
public Transform target;
public Vector3 offset;
public Joystick cameraJoystick;
public float smoothSpeed = 0.1f;
public float rotateSpeed = 90f;
private float offsetRotation = 0;
private Quaternion qRotation = Quaternion.identity;
void Update(){
if (cameraJoystick.Horizontal != 0){
offsetRotation += -cameraJoystick.Horizontal * rotateSpeed * Time.deltaTime;
qRotation = Quaternion.AngleAxis(offsetRotation, Vector3.up);
}
}
void LateUpdate(){
follow();
}
void follow() {
Vector3 desiredPosition = target.position + (qRotation * offset);
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
transform.LookAt(target);
}
}
Thank you, yes it makes sense, i had the idea it would be that but didn't know how to fix it. I tried like this but now the behaviour is not zoom in or zoom out, it's either rotating upwards until it's right above the player, or rotating downards until the camera is touching the ground, in both cases it still faces the player.
public class CameraFollow : $$anonymous$$onoBehaviour
{
//for camera follow
public Transform target;
public float smoothSpeed;
public Vector3 offset;
//for camera rotation
public float speed = 1.5f;
public Joystick cameraJoystick;
public float followDistance;
private void Start()
{
offset = followDistance * offset.normalized;
}
void Update(){
if (cameraJoystick.Horizontal != 0)
{
transform.RotateAround(target.position, Vector3.up, -cameraJoystick.Horizontal * speed);
offset = followDistance * (transform.position - target.position).normalized;
}
}
void LateUpdate()
{
follow();
}
void follow() {
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
transform.LookAt(target);
}
}
Ahh mb, should have realised that would happen. Check out my edit, the key is to not change the value of offset when working out the new position, this means we can't build up errors over time. (You may eventually want to change the value of offset, but that would be when the intent is to increase height or distance of the camera from the target, rather than when rotating around.)
Your edit is working like a charm :) thanks alot!