noxy
noxy

Reputation: 1

Godot Map Zoom is bugged. Why?

The idea: When you zoom in, it should zoom towards the mouse. In some ways, it does, but it snaps and sometimes zooms in the wrong direction.

I tried zooming in and out (as seen in the linked video). For example, zooming in on a corner of the viewport, then zooming out, and then moving my mouse to the other side (in the video, it's the right side), it zooms in to the left.

The Video

Source Code:

extends Node2D

var camera : Camera2D
var zoom_min = null
var zoom_max = Vector2(3, 3)
var zoom_speed = Vector2(0.2, 0.2)
var des_zoom = null

# Called when the node enters the scene tree for the first time.
func _ready():
    # Init the Map from the MapData
    var Map = await load(MapData.MapFile).instantiate()
    Map.name = "Map"
    print_rich("[color=green]Map Loaded: [/color]", Map.name, "\n")
    
    # Add the Map node to the scene tree
    add_child(Map)

    ### Map.position = Vector2(-MapData.map_middlepoint[0], -MapData.map_middlepoint[1])
    
    # Create and configure the Camera2D node
    camera = Camera2D.new()

    # Calculate the required zoom level based on the map's height and the viewport height
    var viewport_size = get_viewport_rect().size
    var map_height = MapData.map_middlepoint[1] * 2
    var zoom_level = viewport_size.y / map_height
    
    # Apply the calculated zoom level to the camera
    camera.zoom = Vector2(zoom_level, zoom_level)

    zoom_min = Vector2(zoom_level, zoom_level)
    des_zoom = Vector2(zoom_level, zoom_level)

    # Calculate the aspect ratio of the viewport
    var viewport_aspect_ratio = viewport_size.x / viewport_size.y
    
    # Calculate the extra space needed on the left and right sides
    var extra_space = (MapData.map_middlepoint[1] * viewport_aspect_ratio)
    print_rich("[color=yellow]Extra Space:[/color] ", extra_space)

    # Setting camera position to the middle of the map
    camera.position = MapData.map_middlepoint # camera starting position



    # Setting limits for the camera with extra space on the left and right sides
    camera.limit_left = -extra_space + MapData.map_middlepoint[0]
    camera.limit_top = 0
    camera.limit_right = extra_space + MapData.map_middlepoint[0]
    camera.limit_bottom = MapData.map_middlepoint[1] * 2
    
    # Add the Camera2D node to the scene tree
    add_child(camera)

    camera.make_current() # Make this camera the current camera
    
    # Print the scene tree
    print_tree_pretty()

func _process(delta):
    camera.zoom = lerp(camera.zoom, des_zoom, 0.1)

    # Get the mouse position
    ### var camera_position = camera.get_global_position()
    ### print_rich("[color=yellow]Camera Position:[/color] ", camera_position, "\n")

func _input(event):
    if event is InputEventMouseButton:
        if Input.is_mouse_button_pressed(MOUSE_BUTTON_WHEEL_DOWN):
            if des_zoom > zoom_min:
                des_zoom -= zoom_speed
                var mouse_position = get_global_mouse_position()
                print_rich("[color=yellow]Mouse Position (Zoom Out):[/color] ", mouse_position)
                var target_position = lerp(camera.position, mouse_position, 0.2)
                target_position.x = clamp(target_position.x, camera.limit_left, camera.limit_right)
                target_position.y = clamp(target_position.y, camera.limit_top, camera.limit_bottom)
                print_rich("[color=yellow]Target Position (Zoom Out):[/color] ", target_position)
                camera.position = target_position
        if Input.is_mouse_button_pressed(MOUSE_BUTTON_WHEEL_UP):
            if des_zoom < zoom_max:
                des_zoom += zoom_speed
                var mouse_position = get_global_mouse_position()
                print_rich("[color=yellow]Mouse Position (Zoom In):[/color] ", mouse_position)
                var target_position = lerp(camera.position, mouse_position, 0.2)
                target_position.x = clamp(target_position.x, camera.limit_left, camera.limit_right)
                target_position.y = clamp(target_position.y, camera.limit_top, camera.limit_bottom)
                print_rich("[color=yellow]Target Position (Zoom In):[/color] ", target_position)
                camera.position = target_position

Upvotes: 0

Views: 50

Answers (1)

Tumbolisu
Tumbolisu

Reputation: 31

The issue mainly stems from calculating target_position from camera.position. You are assuming that camera.position will be within the camera's limits (a very reasonable assumption), but the reality is that camera.position can be literally anything.

Explanation of what you see in the video: You are first moving camera.position to the top-left corner by zooming in and out a lot at that location. Then, as you zoom in on the top-right corner, target_position is first set to 20% between the top-left and top-right corner, then on the next mouse wheel input, another 20% closer, and so on.

Here is what the official engine documentation has to say about this:

Note that the Camera2D node's position doesn't represent the actual position of the screen, which may differ due to applied smoothing or limits. You can use get_screen_center_position to get the real position.

Try using get_screen_center_position like the docs mention. In other words, replace var target_position = lerp(camera.position, mouse_position, 0.2) with var target_position = lerp(camera.get_screen_center_position(), mouse_position, 0.2).

Upvotes: 0

Related Questions