3D Kinematic Car: Chase Camera
Problem
You want a “chase camera” that can follow your car (or any other object).
Solution
Godot has a built-in InterpolatedCamera
node that does most of what’s described here. However, we’re not going to use it for two reasons: first, it has a tendency to stutter when following kinematic bodies, and second, it’s getting removed in Godot 4.0. Setting up our own is really easy though, so don’t worry.
Setting up the camera
Add a new scene with a Camera
. Name it ChaseCamera
, save it, and add a script.
The ChaseCamera
will have a target
- the thing it’s following. We’re also going to include the ability to change that target.
extends Camera
export var lerp_speed = 10.0
var target = null
func _physics_process(delta):
if !target:
return
global_transform = global_transform.interpolate_with(target.global_transform, lerp_speed * delta)
func _on_change_camera(t):
target = t
The only parameter to set here is the lerp_speed
, which controls how quickly the camera updates its position. Set it low, and the camera will “lag” behind the car. Set it high, and it will remain locked on.
Setting up the target(s)
We want to be able to have a few different chase camera positions. One close and one far, for example, or perhaps one looking straight down. Add a Spatial
to the car and name it CameraPositions
. Add a few Position3D
s to this - as many as you would like.
Move and orient each Position3D
in a different location of your choosing. The position’s -Z axis should point at the car.
To communicate to the camera, we’ll emit a signal whenever we want it to change position. Add the following code to the car’s script:
extends "res://cars/car_base.gd"
signal change_camera
var current_camera = 0
onready var num_cameras = $CameraPositions.get_child_count()
func _ready():
emit_signal("change_camera", $CameraPositions.get_child(current_camera))
func _input(event):
if event.is_action_pressed("change_camera"):
current_camera = wrapi(current_camera + 1, 0, num_cameras)
emit_signal("change_camera", $CameraPositions.get_child(current_camera))
Add an action in the InputMap for changing the camera. Here, we’re using Tab and the right shoulder button:
Connecting it together
Add a ChaseCamera
instance to your main scene and set it Current
. Then connect the car’s change_camera
signal to the camera’s _on_change_camera()
function.
Run the game and press the camera change button to try it out: