Godot地图缩放功能异常:鼠标指向缩放失效问题求助
Camera2D缩放时朝向鼠标位置的修复方案
问题概述
需求:Camera2D缩放时镜头应朝向鼠标位置,但当前实现存在画面跳变、偶尔缩放方向错误的问题。
复现步骤:在视口角落放大后缩小,将鼠标移至另一侧(如右侧),镜头会向左侧错误放大。
原代码问题分析
- 位置调整逻辑错误:直接使用全局鼠标位置通过lerp调整相机位置,未遵循"缩放时保持鼠标指向的世界坐标在视口中位置不变"的核心逻辑。
- 画面跳变:在
_input事件中直接设置camera.position,没有和缩放一样做平滑过渡处理。 - 方向错误根源:未结合当前缩放比例计算位置偏移,导致缩放时镜头移动方向与预期相反。
修复后的代码
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)
关键修改说明
- 平滑过渡优化:新增
des_position变量,将位置调整和缩放统一放在_process中用lerp平滑过渡,彻底解决画面跳变问题。 - 核心位置计算:通过
鼠标局部位置与视口中心的偏移量结合缩放变化值计算位置调整量,确保鼠标指向的世界坐标在缩放后始终处于视口同一位置,解决方向错误问题。 - 事件处理优化:仅响应鼠标滚轮的按下事件,避免重复触发导致的异常行为。
- 缩放一致性:使用统一的
zoom_speed数值,保证XY方向缩放比例一致。
内容的提问来源于stack exchange,提问作者noxy
相关产品推荐
相关产品推荐

