feat(stage): complete phase 20b action plans
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
extends SceneTree
|
||||
|
||||
const SANDBOX_STAGE: PackedScene = preload("res://scenes/stage/sandbox_stage.tscn")
|
||||
const STAGE_SELECTION := preload("res://scripts/stage/stage_selection.gd")
|
||||
const STAGE_DIALOG_STYLER := preload("res://scripts/shared/stage_ui/stage_dialog_styler.gd")
|
||||
const CAPTURE_DIR := "res://tests/phase20b_captures/pickup_action_marker"
|
||||
|
||||
var _stage: SandboxStage
|
||||
var _failures: int = 0
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
root.size = Vector2i(1280, 720)
|
||||
root.gui_embed_subwindows = true
|
||||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(CAPTURE_DIR))
|
||||
_stage = SANDBOX_STAGE.instantiate() as SandboxStage
|
||||
root.add_child(_stage)
|
||||
await _wait_frames(10)
|
||||
var recovery: ConfirmationDialog = _stage.find_child("AutosaveRecoveryDialog", true, false) as ConfirmationDialog
|
||||
if recovery != null:
|
||||
STAGE_DIALOG_STYLER.hide(recovery)
|
||||
_stage.call("_on_grid_toggled", false)
|
||||
var spawner: StageSpawner = _stage.get("_spawner") as StageSpawner
|
||||
var world: Node2D = _stage.get_node("World") as Node2D
|
||||
var actor: StickmanRig = spawner.spawn_stickman_asset("res://content/stickmen/break.stk", Vector2(-160.0, -190.0))
|
||||
var prop: PropBlock = spawner.spawn_prop_asset("crate", Vector2(150.0, -10.0))
|
||||
_check(actor != null and prop != null, "production Stage fixture creates a character and pickup target")
|
||||
if actor == null or prop == null:
|
||||
await _finish()
|
||||
return
|
||||
_stage.call("_finalize_placed_node", actor)
|
||||
_stage.call("_finalize_placed_node", prop)
|
||||
var identity: StageObjectIdentity = _stage.get("_object_identity") as StageObjectIdentity
|
||||
var rename_result: Dictionary = identity.rename(prop, "Brown Suitcase", world)
|
||||
_check(bool(rename_result.get("ok", false)), "pickup target receives its friendly stage name")
|
||||
var pickup_action: Dictionary = {
|
||||
"action_id": "pickup-marker-step-one",
|
||||
"type": "pick_up_prop",
|
||||
"target_prop_id": prop.stage_object_id,
|
||||
"hand": "auto",
|
||||
}
|
||||
_check(actor.set_action_plan([{"actions": [pickup_action]}]), "Step 1 receives a real Pick Up Prop action")
|
||||
_stage.call("set_mode", SandboxStage.StageMode.DIRECT)
|
||||
var selection: StageSelection = _stage.get("_selection") as StageSelection
|
||||
selection.select_only(actor)
|
||||
_stage.call("_refresh_character_settings_card")
|
||||
await _wait_frames(8)
|
||||
var visuals: StageDirectorVisuals = _stage.get("_director_visuals") as StageDirectorVisuals
|
||||
var projection: Dictionary = {}
|
||||
for entry: Dictionary in visuals._plan_projection(actor):
|
||||
if String(entry.get("action_id", "")) == String(pickup_action["action_id"]):
|
||||
projection = entry
|
||||
break
|
||||
_check(String(projection.get("kind", "")) == "other" and String((projection.get("action", {}) as Dictionary).get("type", "")) == "pick_up_prop", "pickup action reaches the production Stage overlay projection")
|
||||
var canvas_transform: Transform2D = _stage.get_viewport().get_canvas_transform()
|
||||
var prop_world_bounds: Rect2 = STAGE_SELECTION.get_world_aabb(prop)
|
||||
var prop_screen_bounds: Rect2 = visuals._world_rect_to_screen_rect(prop_world_bounds, canvas_transform)
|
||||
var badge_size: Vector2 = visuals._text_action_badge_screen_size("Pick up", visuals._zoom())
|
||||
var viewport_size: Vector2 = root.size
|
||||
var safe_rect: Rect2 = Rect2(Vector2(8.0, 72.0), Vector2(viewport_size.x - 16.0, viewport_size.y - 112.0))
|
||||
var actor_name_rect: Rect2 = visuals._actor_name_badge_screen_rect(actor, visuals._zoom())
|
||||
var badge_rect: Rect2 = visuals._pickup_badge_screen_rect(prop_screen_bounds, badge_size, safe_rect, actor_name_rect)
|
||||
_check(safe_rect.encloses(badge_rect), "Pick up pill stays inside the visible Stage safe area")
|
||||
_check(not badge_rect.intersects(prop_screen_bounds), "Pick up pill sits outside the target prop bounds")
|
||||
if _can_capture_image():
|
||||
await RenderingServer.frame_post_draw
|
||||
var image: Image = root.get_texture().get_image()
|
||||
var path: String = CAPTURE_DIR.path_join("pickup_step_one_pill_over_prop.png")
|
||||
var save_error: Error = image.save_png(ProjectSettings.globalize_path(path)) if image != null and not image.is_empty() else ERR_CANT_CREATE
|
||||
_check(save_error == OK, "focused Godot run saves the rendered pickup action marker PNG")
|
||||
print("PICKUP_ACTION_MARKER_CAPTURE path=%s size=%s" % [path, str(image.get_size()) if image != null else "missing"])
|
||||
print("PHASE20B_PICKUP_ACTION_MARKER_RESULT failures=%d" % _failures)
|
||||
await _finish()
|
||||
quit(1 if _failures > 0 else 0)
|
||||
|
||||
|
||||
func _wait_frames(count: int) -> void:
|
||||
for _index: int in count:
|
||||
await process_frame
|
||||
|
||||
|
||||
func _can_capture_image() -> bool:
|
||||
var display_name: String = DisplayServer.get_name().to_lower()
|
||||
return not OS.has_feature("headless") and display_name != "headless" and display_name != "dummy"
|
||||
|
||||
|
||||
func _check(condition: bool, message: String) -> void:
|
||||
if condition:
|
||||
print("PASS: %s" % message)
|
||||
else:
|
||||
_failures += 1
|
||||
push_error("FAIL: " + message)
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
if _stage != null and is_instance_valid(_stage):
|
||||
_stage.queue_free()
|
||||
await process_frame
|
||||
Reference in New Issue
Block a user