Signals & Game Events
Godot Fundamentals
Chapter 7 · Signals & Game Events
Chapter 3 declared a first custom signal; Chapter 6 connected a built-in one, body_entered.
Both times, the connection was made entirely from code. This chapter goes deeper: connecting signals visually
in the editor, controlling exactly how a connection behaves, pausing a function until a signal fires, and —
the real point of all of it — using signals to design game systems that don't depend tightly on each other.
Connecting Signals in the Editor
Every connection shown so far has used .connect() in a script. Godot's editor also offers a
fully visual alternative:
- Select a node in the Scene panel.
- Open the Node dock (usually tabbed next to the Inspector) and click "Signals."
- Every signal that node offers — built-in and custom — is listed here.
- Double-click a signal, choose the node that should handle it, and Godot generates a matching handler function automatically, already connected.
pressed signal, wired once at design time). Code-based connections are the better choice when
the connection needs to happen dynamically — for instance, connecting to a signal on a node that was only
just instanced at runtime, the way Chapter 3's spawned scenes were.
One-Shot Connections & Disconnecting
By default a connection stays active and fires every time the signal is emitted, for as long as both nodes exist. Two situations need something different: a connection that should only ever fire once, and a connection that needs to be torn down deliberately, before either node is freed.
queue_free() while A still expects to receive that signal, referencing a
freed node from the handler function raises a real error. Disconnecting explicitly (or using
CONNECT_ONE_SHOT for anything genuinely one-time) avoids this class of bug.
await — Pausing Until a Signal Fires
GDScript's await keyword pauses a function's own execution until a given signal actually
fires, then continues from exactly that point — useful for sequencing things like a short delay, an
animation finishing, or a cutscene waiting for input.
await doesn't freeze the game — unlike a blocking sleep() call in
plain Python, everything else in the game keeps running normally while one function is paused on
await. Only that specific function's own execution is suspended, waiting for its signal.
Designing With Signals: A Decoupled Health System
The real payoff of signals shows up once several systems need to react to the same event without knowing about each other. A health system is the classic example: it shouldn't need to know a health bar, a screen shake effect, or a "low health" warning sound all exist — it should just announce that health changed, and let anything interested react on its own.
A completely separate HUD scene, and a completely separate audio-warning script, can each independently
connect to the exact same health_changed signal — neither needs to know the other exists, and
neither needs any change if a third listener is added later. Chapter 8 builds a real HUD that does exactly
this.
observer patterns, a pub/sub library, or Django's own signal framework, if you've encountered
it — the emitter never imports or references any of its listeners. What's distinctive in Godot is how
lightweight declaring a new one is: a single signal line, no separate event-bus class to set
up, no manual list of callback functions to maintain by hand.
Coding Challenges
pressed
signal to a new handler function that prints "Button clicked!". Confirm it works by running the
scene.
await with
get_tree().create_timer() to pause for 2 seconds, then prints "Go!". Confirm the rest of
the scene (e.g. a spinning sprite from Chapter 4) keeps moving during that 2-second pause rather than
freezing.
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.
Quick Reference — Signals & Game Events
- Node dock > Signals tab — connect visually in the editor; generates a handler automatically
signal_name.connect(handler, CONNECT_ONE_SHOT)— fires once, then auto-disconnectssignal_name.disconnect(handler)— tears down a connection manuallyawait signal_name/await get_tree().create_timer(secs).timeout— pauses one function without freezing the game- Design systems to emit signals about what happened; let listeners react independently, with no direct reference back to the emitter