CHALLENGE 3: Two Independent Listeners on One Signal ==================================================================== TASK ---- Build the health.gd script from this chapter's own example. From two separate, unrelated nodes, each independently connect to its health_changed signal - one printing "HUD: health is now X/Y", the other printing "Audio: low health warning!" only when health drops to 30 or below. Call take_damage() a few times and confirm both listeners react correctly on their own. SCENE STRUCTURE ---------------- Root (Node2D) |-- Health (Node) <- health.gd, the chapter's own example |-- FakeHUD (Node) <- listener 1 |-- FakeAudio (Node) <- listener 2 SOLUTION CODE - health.gd (attached to Health, unchanged from the chapter) ------------------------------------------------------------------------------- extends Node signal health_changed(current: int, max_health: int) signal died var current: int = 100 var max_health: int = 100 func take_damage(amount: int) -> void: current = max(current - amount, 0) health_changed.emit(current, max_health) if current == 0: died.emit() SOLUTION CODE - fake_hud.gd (attached to FakeHUD) ------------------------------------------------------ extends Node func _ready() -> void: get_parent().get_node("Health").health_changed.connect(_on_health_changed) func _on_health_changed(current: int, max_health: int) -> void: print("HUD: health is now ", current, "/", max_health) SOLUTION CODE - fake_audio.gd (attached to FakeAudio) ---------------------------------------------------------- extends Node func _ready() -> void: get_parent().get_node("Health").health_changed.connect(_on_health_changed) func _on_health_changed(current: int, max_health: int) -> void: if current <= 30: print("Audio: low health warning!") TRIGGERING IT (e.g. from Root) ----------------------------------- func _ready() -> void: var health = $Health health.take_damage(30) health.take_damage(30) health.take_damage(30) OUTPUT ------ HUD: health is now 70/100 HUD: health is now 40/100 HUD: health is now 10/100 Audio: low health warning! WHY THIS WORKS AS AN ANSWER ---------------------------- Both FakeHUD and FakeAudio connect to the exact same health_changed signal independently, in their own separate _ready() functions - neither one knows the other exists, and health.gd itself has no reference to either of them at all. This is precisely the decoupled "one emitter, many listeners" design the chapter's own health-system example describes. Each listener reacts differently to the identical emitted data: FakeHUD prints on every single emission regardless of the value, while FakeAudio only prints once current drops to 30 or below - so across three take_damage(30) calls (100 -> 70 -> 40 -> 10), the HUD message appears all three times, but the audio warning only appears once health actually reaches 10, which is the first call where current <= 30 becomes true. Removing FakeAudio entirely, or adding a third listener later, would require zero changes to health.gd - exactly the flexibility signals are meant to provide.