You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot地图缩放功能异常:鼠标指向缩放失效问题求助

Camera2D缩放时朝向鼠标位置的修复方案

问题概述

需求:Camera2D缩放时镜头应朝向鼠标位置,但当前实现存在画面跳变、偶尔缩放方向错误的问题。
复现步骤:在视口角落放大后缩小,将鼠标移至另一侧(如右侧),镜头会向左侧错误放大。

原代码问题分析

  1. 位置调整逻辑错误:直接使用全局鼠标位置通过lerp调整相机位置,未遵循"缩放时保持鼠标指向的世界坐标在视口中位置不变"的核心逻辑。
  2. 画面跳变:在_input事件中直接设置camera.position,没有和缩放一样做平滑过渡处理。
  3. 方向错误根源:未结合当前缩放比例计算位置偏移,导致缩放时镜头移动方向与预期相反。

修复后的代码

extends Node2D

var camera : Camera2D
var zoom_min = null
var zoom_max = Vector2(3, 3)
var zoom_speed = 0.2  # 统一数值,保证XY方向缩放一致
var des_zoom = null
var des_position = Vector2.ZERO  # 新增目标位置变量,用于平滑过渡

# 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_child(Map)

    # Create and configure the Camera2D node
    camera = Camera2D.new()

    # Calculate initial zoom level
    var viewport_size = get_viewport_rect().size
    var map_height = MapData.map_middlepoint[1] * 2
    var zoom_level = viewport_size.y / map_height
    
    camera.zoom = Vector2(zoom_level, zoom_level)
    zoom_min = Vector2(zoom_level, zoom_level)
    des_zoom = Vector2(zoom_level, zoom_level)
    des_position = MapData.map_middlepoint  # 初始化目标位置

    # Calculate aspect ratio and camera limits
    var viewport_aspect_ratio = viewport_size.x / viewport_size.y
    var extra_space = (MapData.map_middlepoint[1] * viewport_aspect_ratio)
    print_rich("[color=yellow]Extra Space:[/color] ", extra_space)

    camera.position = des_position
    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_child(camera)
    camera.make_current()
    print_tree_pretty()

func _process(delta):
    # 统一平滑过渡缩放和位置
    camera.zoom = lerp(camera.zoom, des_zoom, 0.1)
    camera.position = lerp(camera.position, des_position, 0.1)
    # 确保位置不超出限制
    camera.position.x = clamp(camera.position.x, camera.limit_left, camera.limit_right)
    camera.position.y = clamp(camera.position.y, camera.limit_top, camera.limit_bottom)

func _input(event):
    if event is InputEventMouseButton and event.pressed:  # 仅处理按下事件,避免重复触发
        # 获取鼠标在相机局部坐标系中的位置(相对于相机原点的偏移)
        var mouse_local = camera.get_local_mouse_position()
        # 计算缩放变化量
        var zoom_change = Vector2.ZERO
        if event.button_index == MOUSE_BUTTON_WHEEL_UP and des_zoom < zoom_max:
            zoom_change = Vector2(zoom_speed, zoom_speed)
        elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN and des_zoom > zoom_min:
            zoom_change = Vector2(-zoom_speed, -zoom_speed)
        
        if zoom_change != Vector2.ZERO:
            var new_zoom = des_zoom + zoom_change
            # 核心逻辑:调整相机位置,让鼠标指向的世界坐标在缩放后保持在视口同一位置
            var viewport_center = get_viewport_rect().size / 2
            var offset = mouse_local - viewport_center
            var position_adjustment = offset * (new_zoom - des_zoom)
            des_position = camera.position + position_adjustment
            
            # 更新目标缩放
            des_zoom = new_zoom
            # 提前限制目标位置,避免后续clamp导致的跳变
            des_position.x = clamp(des_position.x, camera.limit_left, camera.limit_right)
            des_position.y = clamp(des_position.y, camera.limit_top, camera.limit_bottom)

关键修改说明

  1. 平滑过渡优化:新增des_position变量,将位置调整和缩放统一放在_process中用lerp平滑过渡,彻底解决画面跳变问题。
  2. 核心位置计算:通过鼠标局部位置与视口中心的偏移量结合缩放变化值计算位置调整量,确保鼠标指向的世界坐标在缩放后始终处于视口同一位置,解决方向错误问题。
  3. 事件处理优化:仅响应鼠标滚轮的按下事件,避免重复触发导致的异常行为。
  4. 缩放一致性:使用统一的zoom_speed数值,保证XY方向缩放比例一致。

内容的提问来源于stack exchange,提问作者noxy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 23:36:10