Like the title says, camera systems are neat.
It took me a longer than I would have liked to make the current camera system I have, but after some finagling and diagramming things out, I figured out a system that should be able to be modified for future needs.
We’ll need the Camera that is being moved, the Target the camera is following, the xSpeed and ySpeed we want the camera to move with towards its desired location, and the minimum X/Y and maximum X/Y values for the viewport boundaries in the camera the player will have to adhere by (all four values are limited to a range [0,1]).
First, we find the difference between the Target and the camera’s position.
// Target location - Camera location Vector3 dif = target.position - cam.transform.position;
Next, we find the topRight/botLeft corners of the “buffer zone” we’ve set up in camera’s viewport with the min/max variables. We find out where those points are in world space and then add the difference we found earlier to center it around the Target
// Corners of viewport to worldspace + dif Vector3 topRight = cam.ViewportToWorldPoint(new Vector3(maxX, maxY) + dif; Vector3 botLeft = cam.ViewportToWorldPoint(new Vector3(minX, minY) + dif;
Now we need to find out the offset from the Target the camera should be at. This is broken down into the X-coordinate and Y-coordinate.
Find the proportion between character’s X speed and the max speed. This will have a [-1,1] range (going left has a negative speed), so we convert it to a [0,1] range for the following Lerp function. We Lerp between the min/max X points from the botLeft/topRight points, giving us the X-coordinate the camera should be. We finally Lerp between the camera’s current x position and the destination with xSwitchSpeed for a smooth transition.
// X-offset: How fast is the target moving left/right proportional to maxSpeed? // Has Range [-1,1] convert to [0,1] float destPointX = Mathf.Lerp(botLeft.x, topRight.y, ((character.velocity.x / Players.RunSpeed) + 1) / 2); float finalX = Mathf.Lerp(cam.transform.position.x, destPointX, xSwitchSpeed * Time.deltaTime);
Is the character grounded? If not, the camera should move downwards so the player can see what’s coming. We assign the bottom or top y point and Lerp between the current camera y position and the destination with ySwitchSpeed for a smooth transition.
// Y-offset: Is the player grounded? True: maxY, False: minY float destPointY = c.controller.isGrounded ? topRight.y : botLeft.y; float finalY = Mathf.Lerp(cam.transform.position.y, destPointY, ySwitchSpeed * Time.deltaTime);
Finally, we assign the final resulting Vector to the camera’s position.
c.cam.transform.position = new Vector3(finalX, finalY, -10f);
And that’s pretty much it. There’s probably a way to make it a bit more efficient, and there are some features I could probably add like having an “internal” camera speed for when the camera needs to move with the player inside the “buffer zone”, and an “external” camera speed for if/when the character goes fast enough to outrun the camera and it needs to catch up ASAP (like maybe for a huge drop).
Still, pretty neato.