fix(world-map): 🐛 Fix viewport sizing and scaling in arena mode to prevent layout race conditions and correct hex map rendering

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-04-11 06:49:11 -07:00
parent 6cee670e77
commit 4527ca7737

View file

@ -124,22 +124,33 @@ func _apply_arena_camera_fit() -> void:
if cam == null or not cam.has_method("fit_map_to_viewport"):
return
# Force the ViewportWindowManager Control to the window size.
# Normally Control nodes inside a Node2D parent get sized via their
# anchors-relative-to-the-root-viewport, but in arena mode that
# resize never seems to fire — Control.size stays (0,0), so the
# SubViewport ends up at Godot's minimum (2,2), and the
# SubViewportContainer with stretch=true scales that 2x2 image up
# to the entire window (~500x scale). The hex map then looks like
# it's at zoom 0.45 even though Camera2D.zoom is 0.126. Setting
# both sizes explicitly side-steps the layout race condition.
var win_size: Vector2i = DisplayServer.window_get_size()
var win_size_v: Vector2 = Vector2(win_size)
if vwm is Control:
(vwm as Control).size = win_size_v
var bg_vp: SubViewport = null
if vwm.has_method("get_background_viewport"):
bg_vp = vwm.call("get_background_viewport") as SubViewport
if bg_vp != null:
bg_vp.render_target_update_mode = SubViewport.UPDATE_ALWAYS
# Force the SubViewport to match the actual window size. The default
# layout-driven _sync_background_size in viewport_window_manager.gd
# can leave the SubViewport at its initial ~240x180 if the Control's
# layout hasn't propagated. With stretch=true on the container, that
# tiny SubViewport gets blown up 5x to fill the window — making the
# hex map look like it's at zoom 0.45 even though the Camera2D.zoom
# is 0.126. Setting the size explicitly here side-steps the layout
# race condition.
var win_size: Vector2i = DisplayServer.window_get_size()
bg_vp.size = win_size
# Also resize the SubViewportContainer (the immediate parent of the
# SubViewport) so the stretch math doesn't compound the wrong ratio.
var bg_container: Node = vwm.get_node_or_null("BackgroundViewport")
if bg_container is Control:
(bg_container as Control).size = win_size_v
var viewport: Viewport = _world_map.get_viewport()
if viewport == null:
return
@ -288,15 +299,33 @@ func _capture_viewport_screenshot_async() -> void:
push_warning("[AI ARENA] screenshot save failed: %s" % error_string(err))
return
var diag_zoom: float = -1.0
var diag_subvp_size: Vector2i = Vector2i.ZERO
var diag_vwm_size: Vector2 = Vector2.ZERO
var vwm_diag: Node = _world_map.get_node_or_null("ViewportWindowManager")
if vwm_diag != null and vwm_diag.has_method("get_background_camera"):
var diag_cam: Camera2D = vwm_diag.get_background_camera()
if diag_cam != null:
diag_zoom = diag_cam.zoom.x
if vwm_diag != null:
if vwm_diag is Control:
diag_vwm_size = (vwm_diag as Control).size
if vwm_diag.has_method("get_background_camera"):
var diag_cam: Camera2D = vwm_diag.get_background_camera()
if diag_cam != null:
diag_zoom = diag_cam.zoom.x
if vwm_diag.has_method("get_background_viewport"):
var diag_vp: SubViewport = vwm_diag.call("get_background_viewport") as SubViewport
if diag_vp != null:
diag_subvp_size = diag_vp.size
print(
(
"[AI ARENA] screenshot saved: %s (%dx%d) cam_zoom=%.3f"
% [path, image.get_width(), image.get_height(), diag_zoom]
"[AI ARENA] screenshot saved: %s (%dx%d) cam_zoom=%.3f subvp=%dx%d vwm=%dx%d"
% [
path,
image.get_width(),
image.get_height(),
diag_zoom,
diag_subvp_size.x,
diag_subvp_size.y,
int(diag_vwm_size.x),
int(diag_vwm_size.y),
]
)
)