I am using AddForce() to make a ball move around the scene. The camera follows the ball at a fixed position. This is my camera script:
public class CameraScript : MonoBehaviour {
public GameObject target;
public float xOffset, yOffset, zOffset;
void FixedUpdate() {
Vector3 targetPosition = target.transform.position + new Vector3(xOffset, yOffset, zOffset);
transform.position = targetPosition;
transform.LookAt(target.transform.position);
}
}
This works well, except that the camera doesn’t rotate nicely around the ball. I need the camera to always be behind the player so you can clearly see what is in front of the ball (in the direction you are rolling).
Can I somehow use the velocity of the ball to get the correct camera rotation? My current ball script looks like this
public class BallController : MonoBehaviour {
private PlayerInput playerInput;
private InputAction moveAction;
private Vector3 direction;
private Rigidbody rb;
public float speed = 5f;
void Awake() {
playerInput = GetComponent<PlayerInput>();
moveAction = playerInput.actions.FindAction("Move");
rb = GetComponent<Rigidbody>();
}
void Update() {
Vector2 current = moveAction.ReadValue<Vector2>();
direction = new Vector3(current.x, 0, current.y);
}
void FixedUpdate() {
rb.AddForce(direction * speed);
}
}
You don’t script the camera, you use Cinemachine. Following objects including dead and soft zones and collision avoidance and all that, it’s all handed to you from the Inspector and quite often zero code.
Your use case sounds like the usual 3rd person follow mode which Cinemachine handles all by itself, once set up.
Scenario 1: you did all the work, you discover cinemachine, you keep on with your hacking and hacking and hacking, doing more and more hard camera work.
Scenario 2: you did all the work, you discover cinemachine, you switch to cinemachine.
Notice how both contain “you did all the work” so just remove that part.
It really comes down to how much future work you anticipate getting your camera script working.
If it’s almost there, sure, you’re done, ship it… for sure ship it.
But if you’re likely to want more and more, this might be a time to cut and run.
Only you know this.
I know with writing my own Camera scripts (something I still do all the time when ripping out quick little prototypes), there are a few secret sauces I keep handy:
try to never rotate the camera: only set where it IS and set what it looks AT
when moving either the camera position or what it is looking at position, never move those directly: always low-pass filter it to smooth it out. I almost always use Vector3.Lerp() for this.
Yeah i learned a lot of this the hard way, Why is the camera so jittery!? Another thing you need to keep an eye out for is offsetting that lerp otherwise your character is going to be “in front” of the direction they’re heading and the camera will feel like it’s lagging behind the action, so you gotta add to that position its lerping towards with the player position plus that current velocity vector to some modifier. In my script I check for various states, and sometimes I initiate the lerp to be really snappy and sometimes to be more loose, but you gotta lerp between the lerps!
One is often it is useful to add the player’s velocity vector (scaled by a factor and clamped to a maximum) to their position to come up with the “Look At” point. That way as you go faster, the camera looks “more ahead”. The amount of this “aheadness” needs to be damped as well otherwise it’s annoying.
Another is to be sure you do all your camera calculations AFTER everybody else moves, usually by doing it in LateUpdate(), but sometimes by doing it explicitly, eg., calling your own MyUpdate() after the player has moved.
I will certainly check out Cinemachine! It will probably save a ton of work!
At the moment I am just fooling around with the Unity basics to get the hang of working with Vectors, transforms, directions. I was able to solve a “shoulder camera” using the transform.forward of a rotating player that doesn’t roll:
// camera script, target is the player
Vector3 targetPos = target.transform.position + (target.transform.forward * -2) + offset;
transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref velocity, smoothTime);
transform.LookAt(target.transform.position);
The reason it doesn’t work with a ball is that the transform.forward is literally rolling all over the place.
Now the only problem is that the controls of the rolling ball do not line up with the camera, pressing “forward” should move the ball where the camera is looking.
Perhaps this can be solved by using the left, right controls to actually move the camera around the ball, and when the user presses forward, the ball moves opposite to the camera.