- Introduced a new UI/UX specification document for the Phase 19 Starter Scene Composition, detailing user paths, composition rules for Town Street and Living Room, camera framing, and observable acceptance outcomes. - Implemented a visual capture test for different sky states in the sandbox stage, ensuring proper rendering and visual consistency. - Created a comprehensive test suite for the Phase 19 starter scene composition, validating scene loading, geometry, navigation, and interaction behaviors for both Town Street and Living Room. - Added checks for visual alignment, object placements, and scene transitions to ensure adherence to the new UI/UX specifications.
132 lines
6.0 KiB
GDScript
132 lines
6.0 KiB
GDScript
extends SceneTree
|
|
|
|
const SANDBOX_STAGE: PackedScene = preload("res://scenes/stage/sandbox_stage.tscn")
|
|
const TOWN_STREET_PATH: String = "res://content/stages/starters/town_street.scene"
|
|
const SKY_IDS: Array[StringName] = [&"sky_clear_day", &"sky_cloudy_day", &"sky_sunset", &"sky_starry_night"]
|
|
const CAPTURE_DIR: String = "/private/tmp"
|
|
const TEMP_SCENE_PATH: String = "res://tests/phase19_sky_camera_tmp.scene"
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("_capture_sky_states")
|
|
|
|
|
|
func _capture_sky_states() -> void:
|
|
root.size = Vector2i(1280, 720)
|
|
var stage: SandboxStage = SANDBOX_STAGE.instantiate() as SandboxStage
|
|
root.add_child(stage)
|
|
await _wait_for_render_frames(4)
|
|
var town_loaded: bool = bool(stage.call("_load_scene_from_path", TOWN_STREET_PATH, false))
|
|
print("VISUAL town scene loaded=", town_loaded)
|
|
stage.call("_on_grid_toggled", false)
|
|
var camera: Camera2D = stage.get_node("Camera2D") as Camera2D
|
|
var sky_view: StageSkyView = stage.get("_sky_view") as StageSkyView
|
|
var spawner: StageSpawner = stage.get("_spawner") as StageSpawner
|
|
var stickman: StickmanRig = spawner.spawn_stickman_asset("res://content/stickmen/break.stk", Vector2(0.0, -400.0))
|
|
if stickman != null:
|
|
stage.call("_save_object_state", stickman)
|
|
var scenery_controller: StageSceneryController = stage.get("_scenery_controller") as StageSceneryController
|
|
scenery_controller.begin_background_ground(&"finish_background_grass", Vector2(-900.0, 0.0), Color.WHITE)
|
|
var ground_press: InputEventMouseButton = InputEventMouseButton.new()
|
|
ground_press.button_index = MOUSE_BUTTON_LEFT
|
|
ground_press.pressed = true
|
|
scenery_controller.handle_mouse_button(ground_press, Vector2(-900.0, 0.0), false)
|
|
var ground_release: InputEventMouseButton = InputEventMouseButton.new()
|
|
ground_release.button_index = MOUSE_BUTTON_LEFT
|
|
ground_release.pressed = false
|
|
scenery_controller.handle_mouse_button(ground_release, Vector2(900.0, 900.0), false)
|
|
scenery_controller.exit_tool()
|
|
print("VISUAL action context stickman=", stickman != null, " background_ground_count=", (stage.get_node("World") as Node2D).get_children().filter(func(child: Node) -> bool: return child.get_script() == preload("res://scripts/stage/scenery/stage_background_ground.gd")).size())
|
|
await _wait_for_render_frames(4)
|
|
for sky_id: StringName in SKY_IDS:
|
|
camera.global_position = Vector2(0.0, -400.0)
|
|
camera.zoom = Vector2.ONE * 0.5
|
|
stage.set("_sky_id", sky_id)
|
|
sky_view.set_sky(sky_id)
|
|
await _wait_for_render_frames(2)
|
|
await _save_capture("sky_%s_reference.png" % String(sky_id))
|
|
|
|
stage.set("_sky_id", &"sky_sunset")
|
|
sky_view.set_sky(&"sky_sunset")
|
|
camera.global_position = Vector2(420.0, -210.0)
|
|
camera.zoom = Vector2.ONE * 1.5
|
|
await _wait_for_render_frames(3)
|
|
await _save_capture("sky_sunset_close_pan.png")
|
|
|
|
camera.global_position = Vector2(-620.0, -740.0)
|
|
camera.zoom = Vector2.ONE * 0.12
|
|
await _wait_for_render_frames(3)
|
|
await _save_capture("sky_sunset_wide_pan.png")
|
|
|
|
camera.global_position = Vector2(0.0, -400.0)
|
|
camera.zoom = Vector2.ONE * 0.5
|
|
await _wait_for_render_frames(3)
|
|
root.size = Vector2i(900, 700)
|
|
await _wait_for_render_frames(4)
|
|
await _save_capture("sky_sunset_resize_900x700.png")
|
|
stage.set("_sky_id", &"sky_starry_night")
|
|
sky_view.set_sky(&"sky_starry_night")
|
|
await _wait_for_render_frames(3)
|
|
await _save_capture("sky_starry_night_resize_900x700.png")
|
|
root.size = Vector2i(1440, 720)
|
|
await _wait_for_render_frames(4)
|
|
stage.set("_sky_id", &"sky_sunset")
|
|
sky_view.set_sky(&"sky_sunset")
|
|
await _wait_for_render_frames(3)
|
|
await _save_capture("sky_sunset_resize_1440x720.png")
|
|
stage.set("_sky_id", &"sky_starry_night")
|
|
sky_view.set_sky(&"sky_starry_night")
|
|
await _wait_for_render_frames(3)
|
|
await _save_capture("sky_starry_night_resize_1440x720.png")
|
|
root.size = Vector2i(1280, 720)
|
|
stage.set("_sky_id", &"sky_sunset")
|
|
sky_view.set_sky(&"sky_sunset")
|
|
|
|
stage.set("_cli_startup", true)
|
|
stage.call("set_mode", 1)
|
|
await _wait_for_render_frames(3)
|
|
await _save_capture("sky_sunset_direct.png")
|
|
stage.call("set_mode", 2)
|
|
await _wait_for_render_frames(3)
|
|
await _save_capture("sky_sunset_play.png")
|
|
stage.call("set_mode", 0)
|
|
await _wait_for_render_frames(3)
|
|
stage.set("_cli_startup", false)
|
|
await _save_capture("sky_sunset_play_stopped_edit.png")
|
|
|
|
camera.global_position = Vector2(420.0, -210.0)
|
|
camera.zoom = Vector2.ONE * 1.5
|
|
await _wait_for_render_frames(3)
|
|
var saved_shift: Vector2 = sky_view.get("_motif_shift")
|
|
var saved_scale: float = float(sky_view.get("_motif_scale"))
|
|
var saved_camera_position: Vector2 = camera.global_position
|
|
var saved_camera_zoom: Vector2 = camera.zoom
|
|
var saved: bool = stage.call("_save_scene_to_path", TEMP_SCENE_PATH, false)
|
|
var reopened: bool = bool(stage.call("_load_scene_from_path", TEMP_SCENE_PATH, false)) if saved else false
|
|
await _wait_for_render_frames(4)
|
|
var reopened_shift: Vector2 = sky_view.get("_motif_shift")
|
|
var reopened_scale: float = float(sky_view.get("_motif_scale"))
|
|
print("VISUAL sky save/reopen saved=", saved, " reopened=", reopened, " camera=", saved_camera_position, "/", saved_camera_zoom, " reopened_camera=", camera.global_position, "/", camera.zoom, " shift=", saved_shift, "/", reopened_shift, " scale=", saved_scale, "/", reopened_scale, " framing_matches=", saved_shift.is_equal_approx(reopened_shift) and is_equal_approx(saved_scale, reopened_scale))
|
|
await _save_capture("sky_sunset_save_reopen.png")
|
|
if FileAccess.file_exists(TEMP_SCENE_PATH):
|
|
DirAccess.remove_absolute(ProjectSettings.globalize_path(TEMP_SCENE_PATH))
|
|
stage.call("_load_scene_from_path", "res://content/stages/starters/blank.scene", false)
|
|
await _wait_for_render_frames(3)
|
|
stage.queue_free()
|
|
await process_frame
|
|
quit(0)
|
|
|
|
|
|
func _wait_for_render_frames(count: int) -> void:
|
|
for _frame: int in count:
|
|
await process_frame
|
|
await RenderingServer.frame_post_draw
|
|
|
|
|
|
func _save_capture(file_name: String) -> void:
|
|
await RenderingServer.frame_post_draw
|
|
var image: Image = root.get_texture().get_image()
|
|
var path: String = CAPTURE_DIR.path_join("phase19_" + file_name)
|
|
var error: Error = image.save_png(path)
|
|
print("VISUAL capture=", path, " size=", image.get_size(), " error=", error)
|