feat(test): ✅ add capital zoom and hud overlay for render proof
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
8796e7a06d
commit
8fc97ffaed
1 changed files with 90 additions and 14 deletions
|
|
@ -281,16 +281,62 @@ func _build_renderers() -> void:
|
|||
var world_per_screen: float = max(fit_x, fit_y)
|
||||
var zoom_factor: float = 1.0 / max(world_per_screen, 0.001)
|
||||
|
||||
_camera_overview_pos = center
|
||||
_camera_overview_zoom = zoom_factor
|
||||
|
||||
# Capital-zoom preset: 9-tile wide window centred on player 0's
|
||||
# starting capital. The renderer's procedural unit circle is ~30 px
|
||||
# wide which is invisible at the overview zoom (a duel-map fits
|
||||
# 1920×1080 with sub-pixel unit dots); capital zoom shows units and
|
||||
# city sprites unambiguously. Falls back to map centre if start_positions
|
||||
# is empty.
|
||||
var capital_axial: Vector2i = Vector2i.ZERO
|
||||
if _game_map.start_positions.size() > 0:
|
||||
capital_axial = _game_map.start_positions[0]
|
||||
_camera_capital_pos = HexUtilsScript.axial_to_pixel(capital_axial)
|
||||
_camera_capital_zoom = float(VIEWPORT_SIZE.x) / (9.0 * 384.0)
|
||||
|
||||
_camera = Camera2D.new()
|
||||
_camera.name = "DemoCamera"
|
||||
_camera.position = center
|
||||
_camera.zoom = Vector2(zoom_factor, zoom_factor)
|
||||
_camera.position = _camera_overview_pos
|
||||
_camera.zoom = Vector2(_camera_overview_zoom, _camera_overview_zoom)
|
||||
add_child(_camera)
|
||||
# `make_current` is a no-op until the node is inside the tree, so it
|
||||
# MUST come after `add_child`. The reverse order spams a Camera2D
|
||||
# warning at boot and silently drops the activation.
|
||||
_camera.make_current()
|
||||
|
||||
# HUD overlay so each PNG carries the turn number + Claude's scoreboard
|
||||
# state in-frame. Without this, a reviewer can't tell two screenshots
|
||||
# apart at a glance — the unit dots are sub-pixel.
|
||||
_hud_layer = CanvasLayer.new()
|
||||
_hud_layer.name = "HUDLayer"
|
||||
add_child(_hud_layer)
|
||||
_hud_label = Label.new()
|
||||
_hud_label.name = "HUDLabel"
|
||||
_hud_label.position = Vector2(24, 24)
|
||||
_hud_label.add_theme_color_override("font_color", Color(1, 1, 1, 1))
|
||||
_hud_label.add_theme_color_override("font_outline_color", Color(0, 0, 0, 1))
|
||||
_hud_label.add_theme_constant_override("outline_size", 6)
|
||||
_hud_label.add_theme_font_size_override("font_size", 28)
|
||||
_hud_layer.add_child(_hud_label)
|
||||
|
||||
|
||||
func _set_camera_to(mode: String) -> void:
|
||||
if _camera == null:
|
||||
return
|
||||
if mode == "capital":
|
||||
_camera.position = _camera_capital_pos
|
||||
_camera.zoom = Vector2(_camera_capital_zoom, _camera_capital_zoom)
|
||||
else:
|
||||
_camera.position = _camera_overview_pos
|
||||
_camera.zoom = Vector2(_camera_overview_zoom, _camera_overview_zoom)
|
||||
|
||||
|
||||
func _set_hud(text: String) -> void:
|
||||
if _hud_label != null:
|
||||
_hud_label.text = text
|
||||
|
||||
|
||||
# ── Main loop ─────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -299,7 +345,7 @@ func _drive_game() -> void:
|
|||
var initial_view: Dictionary = _request_view()
|
||||
_rehydrate_view(initial_view)
|
||||
await _flush_render()
|
||||
_capture_screenshot(0)
|
||||
await _capture_screenshot(0)
|
||||
_turn_records.append({
|
||||
"turn": 0,
|
||||
"claude_actions": [],
|
||||
|
|
@ -350,7 +396,7 @@ func _drive_game() -> void:
|
|||
_turn_records.append(record)
|
||||
|
||||
if turn_idx % _screenshot_every == 0 or turn_idx == _max_turns:
|
||||
_capture_screenshot(turn_idx)
|
||||
await _capture_screenshot(turn_idx)
|
||||
|
||||
# GameOver check — any event with type=game_over terminates.
|
||||
if _events_contain_game_over(record["end_turn_events"]):
|
||||
|
|
@ -580,17 +626,47 @@ func _flush_render() -> void:
|
|||
|
||||
|
||||
func _capture_screenshot(turn_idx: int) -> void:
|
||||
var image: Image = get_viewport().get_texture().get_image()
|
||||
if image == null:
|
||||
push_error("viewport image null at turn %d" % turn_idx)
|
||||
return
|
||||
var path: String = "%s/turn-%02d.png" % [_output_dir_abs, turn_idx]
|
||||
var err: Error = image.save_png(path)
|
||||
if err == OK:
|
||||
_captured_turns.append(turn_idx)
|
||||
print("SCREENSHOT_TURN:%02d:%s" % [turn_idx, path])
|
||||
# Per-turn HUD overlay carries the turn + Claude's scoreboard so each
|
||||
# PNG is self-identifying. Updated before each capture pose.
|
||||
var scoreboard: String = "Turn %d" % turn_idx
|
||||
if _turn_records.size() > 0:
|
||||
var rec: Dictionary = _turn_records[-1] as Dictionary
|
||||
var scores: Array = rec.get("scores", []) as Array
|
||||
if scores.size() > 0:
|
||||
var s0: Dictionary = scores[0] as Dictionary
|
||||
scoreboard = "Turn %d • Claude (slot %d) gold %d cities %d units %d" % [
|
||||
turn_idx, _claude_slot,
|
||||
int(s0.get("gold", 0)),
|
||||
int(s0.get("cities", 0)),
|
||||
int(s0.get("units", 0)),
|
||||
]
|
||||
|
||||
var modes: Array[String] = []
|
||||
if _zoom_mode == "both":
|
||||
modes = ["overview", "capital"]
|
||||
elif _zoom_mode == "capital":
|
||||
modes = ["capital"]
|
||||
else:
|
||||
push_error("save_png failed turn=%d err=%s" % [turn_idx, error_string(err)])
|
||||
modes = ["overview"]
|
||||
|
||||
for mode: String in modes:
|
||||
_set_camera_to(mode)
|
||||
_set_hud("%s [%s]" % [scoreboard, mode])
|
||||
# Give the engine 2 frames to apply camera change + HUD text + redraw.
|
||||
for _i: int in range(2):
|
||||
await get_tree().process_frame
|
||||
var image: Image = get_viewport().get_texture().get_image()
|
||||
if image == null:
|
||||
push_error("viewport image null at turn %d (%s)" % [turn_idx, mode])
|
||||
continue
|
||||
var suffix: String = "" if _zoom_mode != "both" else ("-" + mode)
|
||||
var path: String = "%s/turn-%02d%s.png" % [_output_dir_abs, turn_idx, suffix]
|
||||
var err: Error = image.save_png(path)
|
||||
if err == OK:
|
||||
_captured_turns.append(turn_idx)
|
||||
print("SCREENSHOT_TURN:%02d:%s:%s" % [turn_idx, mode, path])
|
||||
else:
|
||||
push_error("save_png failed turn=%d mode=%s err=%s" % [turn_idx, mode, error_string(err)])
|
||||
|
||||
|
||||
# ── Recap ─────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue