Refactor rhythm action architecture

This commit is contained in:
wxm
2026-07-02 09:47:52 -07:00
parent fc941cf08d
commit e62ed84518
124 changed files with 7516 additions and 2440 deletions

View File

@@ -4,80 +4,82 @@ var failures: Array[String] = []
func _init() -> void:
var scene: PackedScene = load("res://scenes/main/main.tscn")
_run.call_deferred()
func _run() -> void:
_check_energy_bar_scene_has_editor_segments()
var scene: PackedScene = load("res://scenes/ui/main_ui.tscn")
if scene == null:
push_error("Could not load main.tscn")
push_error("Could not load main_ui.tscn")
quit(1)
return
var main: Node = scene.instantiate()
get_root().add_child(main)
var player: Node = main.get_node_or_null("Player")
if player == null:
failures.append("Missing Player")
elif not player.has_signal("combo_window_cleared"):
failures.append("Player should expose combo_window_cleared")
if not main.has_method("_play_combo_clear_animation"):
failures.append("Main should implement _play_combo_clear_animation")
if not main.has_method("_on_energy_changed"):
failures.append("Main should implement _on_energy_changed")
if not main.has_method("_on_health_changed"):
failures.append("Main should implement _on_health_changed")
if not main.has_method("_on_charge_changed"):
failures.append("Main should implement _on_charge_changed")
var status_bars: Node = main.get_node_or_null("RhythmFeedback/StatusBars")
if status_bars == null:
failures.append("Missing StatusBars")
else:
var health_bar := status_bars.get_node_or_null("HealthBar")
if health_bar == null:
failures.append("Missing HealthBar")
elif not health_bar is ProgressBar:
failures.append("HealthBar should be a ProgressBar")
var energy_bar := status_bars.get_node_or_null("EnergyBar")
if energy_bar == null:
failures.append("Missing EnergyBar")
else:
for index: int in range(10):
var segment := energy_bar.get_node_or_null("Segment%d" % index)
if segment == null:
failures.append("Missing energy segment %d" % index)
elif not segment is Panel:
failures.append("Energy segment %d should be a Panel" % index)
var charge_bar := status_bars.get_node_or_null("ChargeBar")
if charge_bar == null:
failures.append("Missing ChargeBar")
elif not charge_bar is ProgressBar:
failures.append("ChargeBar should be a ProgressBar")
elif main.has_method("_on_charge_changed") and main.has_method("_update_charge_bar_flash"):
main.set("charge_bar", charge_bar)
main.call("_on_charge_changed", 1.1, 1.1, true, true)
main.call("_update_charge_bar_flash", 0.13)
var flashing_alpha: float = charge_bar.modulate.a
main.call("_on_charge_changed", 1.1, 1.1, true, true)
if is_equal_approx(charge_bar.modulate.a, 1.0):
failures.append("Ready charge updates should not reset ChargeBar flash alpha")
if not is_equal_approx(charge_bar.modulate.a, flashing_alpha):
failures.append("Ready charge updates should preserve ChargeBar flash alpha")
var combo_window: Node = main.get_node_or_null("RhythmFeedback/ComboWindow")
if combo_window == null:
failures.append("Missing ComboWindow")
else:
for index: int in range(4):
var slot := combo_window.get_node_or_null("Slot%d" % index)
if slot == null:
failures.append("Missing visual slot %d" % index)
continue
if not slot is PanelContainer:
failures.append("Slot%d should be a PanelContainer" % index)
if slot.get_node_or_null("Key") == null:
failures.append("Slot%d should contain Key label" % index)
main.free()
var ui := scene.instantiate()
root.add_child(ui)
await process_frame
_expect_node(ui, "RhythmTrack", "UI should include RhythmTrack")
_expect_node(ui, "ComboWindow", "UI should include ComboWindow")
_expect_node(ui, "StatusBars/HealthBar", "UI should include HealthBar")
_expect_node(ui, "StatusBars/EnergyBar", "UI should include EnergyBar")
_expect_node(ui, "StatusBars/ChargeBar", "UI should include ChargeBar")
var combo_window := ui.get_node("ComboWindow")
_expect_bool(combo_window.get_child_count() >= 4, true, "ComboWindowHud should build four visual slots")
var bus := _event_bus()
bus.emit_signal("player_health_changed", 42, 100)
bus.emit_signal("player_energy_changed", 3.0, 10.0)
bus.emit_signal("player_charge_changed", 0.8, 1.1, false, true)
bus.emit_signal("combo_updated", [&"A", &"SP"])
await process_frame
var health_bar := ui.get_node("StatusBars/HealthBar") as ProgressBar
var charge_bar := ui.get_node("StatusBars/ChargeBar") as ProgressBar
_expect_float(float(health_bar.value), 42.0, "HealthBar should follow EventBus health")
_expect_float(float(charge_bar.value), 0.8, "ChargeBar should follow EventBus charge")
ui.free()
_finish()
func _check_energy_bar_scene_has_editor_segments() -> void:
var scene: PackedScene = load("res://scenes/ui/energy_bar.tscn")
if scene == null:
failures.append("Could not load energy_bar.tscn")
return
var energy_bar := scene.instantiate()
_expect_bool(energy_bar.get_child_count() == 10, true, "EnergyBar scene should contain ten editor-visible segments before _ready")
energy_bar.free()
func _event_bus() -> Node:
var bus := root.get_node_or_null("EventBus")
if bus == null:
bus = load("res://autoload/event_bus.gd").new()
bus.name = "EventBus"
root.add_child(bus)
return bus
func _expect_node(node: Node, path: String, label: String) -> void:
if node.get_node_or_null(path) == null:
failures.append(label)
func _expect_bool(actual: bool, expected: bool, label: String) -> void:
if actual != expected:
failures.append("%s: expected %s, got %s" % [label, expected, actual])
func _expect_float(actual: float, expected: float, label: String) -> void:
if not is_equal_approx(actual, expected):
failures.append("%s: expected %.3f, got %.3f" % [label, expected, actual])
func _finish() -> void:
if failures.is_empty():
print("PASS combo hud")
quit(0)