Search code examples
camera2dgodotgdscriptgodot4

gdscript Camera2D zooming issues (beginner help)


I am making a 2D platformer and I am having issues with my Camera2D. I already have code that lerps the camera to the player's location. And now i'm trying to implement a system that increases the camera zoom if the player moves (presses any movement keys A, D, space, e.g.), and this is my code so far:

extends Camera2D

@onready var player = $"../player"
@onready var target_zoom: Vector2 = Vector2(0.0, 0.0)

const X_LERP_SPEED: float = 0.1
const Y_LERP_SPEED: float = 0.1

const ZOOM_LERP_SPEED: float = 0.1


func _process(delta):
    if Input.is_action_pressed("move_left") or Input.is_action_pressed("move_left") or Input.is_action_pressed("jump"): # if the player moves
        if target_zoom.x <= 0.1: # trying to make zoom smaller if until it reaches 0.1
            target_zoom.x -= 0.01
            target_zoom.y -= 0.01
    else:
        target_zoom = lerp(target_zoom, Vector2(1.0, 1.0), ZOOM_LERP_SPEED * delta) # trying to increase the zoom until it reaches 1 (which is normal size)

    zoom = lerp(zoom, target_zoom * delta, ZOOM_LERP_SPEED) # trying to lerp the Camera2D's zoom property to target_zoom

    # smoothly follows the player (currently the only working thing)
    position.x = lerp(position.x, (player.global_position.x + position.x) / 2, X_LERP_SPEED)
    position.y = lerp(position.y, (player.global_position.y + position.y) / 2, Y_LERP_SPEED)

note: the camera is not a child of the player node.

as you can see, i'm a beginner and is having issues with lerping values, placing * delta and ect.

What I'm trying to achive: the camera stays at regular size (1) when it's not moving, it zooms out when it it moving, and zooms back in to 1 when the player is not moving.


Solution

  • You seem to be on the right track, but as you noted, your use of deltas was causing things to scale in weird and unexpected ways. Your logic also had some mistakes in it, so I figured it would be easiest to show you the way that I would approach this:

    extends Camera2D
    
    @onready var player = $"../player"
    
    # Define the maximum and minimum amount that the camera can zoom
    const min_zoom: Vector2 = Vector2(0.1, 0.1)
    const max_zoom: Vector2 = Vector2.ONE
    
    # Used to keep track of how zoomed the camera currently is. 
    # Note: Ideally, this is assigned using inverse_lerp(min_zoom, max_zoom, zoom), 
    #   but unfortunately Godot currently doesn't support Vector2 inverse_lerp.
    # Note: Due to note above, if you want to use a different starting zoom, 
    #   this value needs to be updated to match.
    @onready var zoom_progress: float = 1.0
    
    const ZOOM_OUT_SPEED: float = 0.5
    const ZOOM_IN_SPEED: float = 1
    
    const X_LERP_SPEED: float = 0.1
    const Y_LERP_SPEED: float = 0.1
    
    func _process(delta):
        # Change zoom_progress based on whether the player is pressing input or not
        if Input.is_action_pressed("move_left") or Input.is_action_pressed("move_right") or Input.is_action_pressed("jump"): # if the player moves
            zoom_progress = clamp(zoom_progress - ZOOM_OUT_SPEED * delta, 0, 1)
        else:
            zoom_progress = clamp(zoom_progress + ZOOM_IN_SPEED * delta, 0, 1)
    
        zoom = lerp(min_zoom, max_zoom, zoom_progress)
    
        # smoothly follows the player (currently the only working thing)
        position.x = lerp(position.x, (player.global_position.x + position.x) / 2, X_LERP_SPEED)
        position.y = lerp(position.y, (player.global_position.y + position.y) / 2, Y_LERP_SPEED)
    

    I left your movement logic alone as you said that it seems to work for you currently.

    The big change that I made is storing a zoom_progress variable to keep track of how zoomed the camera is, and adjusting it based on input.

    I also added the ability to have different zooming in and zooming out speeds, as in my experience you want the camera to zoom in faster than it zooms out, but feel free to change it back to a single speed if this doesn't fit your needs!

    Another adjustment was moving the minimum zoom from Vector2.ZERO to Vector2(0.1, 0.1), as Godot doesn't like cameras to have a zoom of zero and throws warnings if you try.

    If you want to get a better grasp on using delta, this video by Jonas Tyroller helped me a lot to understand the basics, and I refer back to it often when I start to get confused!