Celeste like camera

Godot Version

4.5.1 Steam

Celeste like camera and transitions

I’m trying to implement a camera similar to Celeste in my 2D platform project. The main difference is that I want the camera to zoom in to fit the room it’s in. I’ve managed to implement the camera’s limits per room and the necessary zoom per room, but I’m still not satisfied with the camera’s movement following the player, nor have I been able to create a decent implementation for the room transition that Celeste has.

The camera is instantiated in a scene that I use as a level controller, which instantiates the camera and uses the function: setup(player)

giving the player node to the camera.

extends Camera2D
class_name CameraController

# ==============
# exports
# ==============

@export var min_zoom := 0.1
@export var max_zoom := 10.0

# ==============
# control
# ==============

var target: Node2D
var room_rect : Rect2
var father : Node2D

# ==============
# Ready?
# ==============

func _ready() -> void:
	father = get_parent()
	if father.has_signal("current_room_changed"):
		father.current_room_changed.connect(new_room)
	make_current()
	process_mode = Node.PROCESS_MODE_ALWAYS

# ==============
# Setup
# ==============

func setup(player : Node2D) -> void:
	target = player

# ==============
# New Room
# ==============

func new_room(room : RoomBase, snap : bool = false) -> void:
	room_rect = room.exrect
	limits_set(room_rect)
	zooming(room_rect)

# ==============
# zoomming
# ==============

func zooming(rect : Rect2) -> void:
	var viewport_size = get_viewport_rect().size
	var room_size := rect.size
	
	if room_size.x <= 0 or room_size.y <= 0:
		push_error("Erro")
	
	var req_zoom_x = viewport_size.x / room_size.x
	var req_zoom_y = viewport_size.y / room_size.y
	
	var target_zoom = max(req_zoom_x, req_zoom_y)
	target_zoom = clamp(target_zoom, min_zoom, max_zoom)
	zoom = Vector2(target_zoom, target_zoom)

# ==============
# Limits set
# ==============

func limits_set(rect : Rect2) -> void:
	
	limit_left   = int(rect.position.x)
	limit_top    = int(rect.position.y)
	limit_right  = int(rect.end.x)
	limit_bottom = int(rect.end.y)
	

# ==============
# Follow Target
# ==============

func follow_target(target : Node2D, delta : float) -> void:
	var targete = target.global_position
	var targete_pos_x
	var targete_pos_y
	targete_pos_x = int(lerp(global_position.x, targete.x, 0.3)) 
	targete_pos_y = int(lerp(global_position.y, targete.y, 0.3)) 
	global_position = Vector2(targete_pos_x, targete_pos_y)


# ==============
# Physics Process
# ==============

func _process(delta: float) -> void:
	if target:
		follow_target(target, delta)

Try just adding the camera as a child of your Player instead of using your follow_target() code, and then playing with the Position Smoothing setting.

1 Like