G2.8 — Running, Debugging & the Remote Tree¶
What you'll learn
- Run the right target: F5 (main scene) versus F6 (current scene).
- Read the Output and Debugger docks, set breakpoints, and step through code.
- Inspect and tweak the live game with the Remote scene tree.
- See the full hand-off: every concept here mapped to where the game books first need it.
How it applies
- Without observability you debug by guesswork. If you cannot see a running node's actual state, you theorize instead of looking. The remote tree and the debugger turn "I think it's null" into "I can see it is null," which is the difference between a fix and a guess.
- Breakpoints beat scattering
prints. A breakpoint pauses the whole game at a line and lets you inspect every variable at that instant, without editing and re-running for each value. For anything past a trivial check, it is the faster instrument. - The stack trace points past the symptom. The crash line is where a bad value was used; the trace is how it got there (L2.4). Reading the trace is how you fix causes instead of symptoms.
- Running the wrong target wastes every iteration. Launching the whole game to test one scene buries what you changed; F6 runs the scene in isolation. Small, but it compounds over a day.
Concepts¶
Running: F5 versus F6¶
As in L1.1: F5 runs the project's main scene (the game from its entry point); F6 runs the current scene by itself. Test a piece in isolation with F6; check the whole game with F5. Reaching for the wrong one is a small, constant tax on iteration.
The Output and Debugger docks¶
- The Output dock shows
print,push_warning, andpush_errortext (L1.1, L2.4). It is the cheapest instrument: aprintconfirms a line ran and what a value was. - The Debugger dock activates on a runtime error or a breakpoint. It shows the error message, the stack trace (the chain of calls that reached the failure), and panels for the call stack and variables. When the game errors, this is where you read why and how it got there — not just the last line.
print_debug(value) is a print that also reports the file and line it was called from — handy when
several prints would otherwise be indistinguishable.
Breakpoints and stepping¶
Click the gutter beside a line in the script editor (or write breakpoint) to set a breakpoint.
When execution reaches it, the game pauses and the editor shows the full state at that moment:
- Step Over runs the next line without descending into its function calls.
- Step Into descends into the called function.
- Continue resumes until the next breakpoint.
- The Stack and Variables panels let you read every local and member at the paused instant.
A breakpoint inspects the entire state at a point in time without editing code — strictly more than a
print, which shows one value and requires a re-run to add another. For tracing how a value became
wrong, pause near the failure and read the variables.
The Remote scene tree¶
While the game runs, the editor's Scene dock offers a Remote tab: the live tree of the running
game. Select a running node there and the Inspector shows — and lets you edit — its current
properties, live. You can watch an enemy's position change, confirm a node exists (or does not),
flip a flag, and see the effect immediately.
This is the primary live-observability surface, and the QA framing is exact: it is the running program's instrument panel. "Is the node even in the tree?" (the orphan bug, G1.2), "what is this value right now?", "did this node get freed?" — the remote tree answers all three by showing you, rather than by inference. The Monitors tab adds performance graphs (frame time, memory, draw calls) for when the question is "why is it slow," not "why is it wrong."
Example
Diagnosing a "call on Nil" (L2.4) with the tools, not guesses:
- The Debugger shows the error and the line
enemy.take_damage(5)—enemyis null. - Set a breakpoint just before that line and re-run to the pause.
- In the Variables panel, read
enemy: confirm it isnullrather than assuming. - Walk the stack back to where
enemywas assigned; in the Remote tree, check whether the node it should have referenced is actually present.
Each step observes rather than theorizes. The remote tree and debugger convert L2.4's "read the error and trace the cause" from a thought experiment into something you can watch.
The hand-off: what you can now read¶
This is the last chapter, so here is the contract the book set out to fulfill — every Foundations concept mapped to where the game books first rely on it. When a game-book chapter uses one of these without explanation, it is because it lives here:
| Game-book chapter assumes… | Foundations source |
|---|---|
ARPG M1.2 / idle M1.2 — preload, res:// paths |
G1.1, G1.3 |
| ARPG M1.4 — SignalBus (autoload + custom signals) | L2.3 (signal/emit), G1.5 (autoload), G2.6 (connect) |
ARPG M1.3 / idle — InputMap, Input.get_vector |
G2.5, L1.6 |
ARPG M2.1 — CharacterBody2D, _physics_process, move_and_slide |
G2.1, G2.7, L1.6 |
ARPG M2.2 — @onready, $, AnimatedSprite2D, flip_h |
L2.2, G1.4, G2.3 |
ARPG M2.3 — Camera2D follow |
G2.3 |
ARPG M2.4 — node FSM (enum, match, class_name, is, child nodes, transitioned signal) |
L1.3, L2.1, L2.3, G1.2 |
ARPG M3.1 — Area2D, collision layers/masks, as cast |
G2.7, L2.1 |
ARPG M3.2 — Health component (@export, property setter, signal) |
L2.2, L2.3 |
ARPG M3.3 — CONNECT_ONE_SHOT, await animation_finished, node paths |
G2.6, L2.3, G1.4 |
| ARPG M5 / M6 — StatBlock, ItemData custom Resources | G1.6, L2.1, L2.2 |
ARPG M6.3 — weighted drop tables (Array, randi_range) |
L1.5, L1.6 |
idle M1.4 — Control, containers, anchors, size flags |
G2.4 |
idle M2.1 — Button.pressed, @onready, %-format text |
G2.6, L2.2, L1.2 |
idle M2.2 — class_name, property setter, emit |
L2.1, L2.2, L2.3 |
| idle M2.3 — autoload registration, lambda handler | G1.5, L1.4 |
idle M3.1 — _process, delta, accumulator (while) |
G2.1, L1.3 |
If any concept a game book uses at its start is missing from this table, that is a gap to report; if every row resolves, you are equipped to work on those books rather than follow them.
Walkthrough¶
- Reproduce a runtime error (reuse the null-
$Childsetup from L2.4). Run, and read the Debugger: the message, then the stack trace. Identify the failing line and the call that led to it. - Set a breakpoint on the line before the failure. Re-run; when it pauses, read the Variables
panel and confirm the offending value is what you suspected (e.g.
null). Use Step Over to advance one line. - With a moving node (your G2.1/G2.7 player), run, open the Remote scene tree, select the player,
and watch its
positionupdate live in the Inspector as you move. Change a property there and see the running game react. - Open the Monitors tab and watch frame time as the scene runs — the surface you would use for a performance question rather than a correctness one.
Optional sanity check
Recreate the orphan bug from G1.2: Node.new() without add_child. Run and check the Remote
tree — the node is not there, confirming it never entered the tree. Add add_child and watch it
appear in the remote tree. The remote tree answers "is it even in the tree?" by showing you, which
is the whole value of live observability.
Self-check quiz¶
Q1 — Why is a breakpoint often better than adding print statements?
A. Breakpoints make the game run faster.
B. A breakpoint pauses the game and exposes every variable at that instant, without editing and re-running for each value a print would show.
C. print does not work in Godot.
D. Breakpoints automatically fix the bug.
Reveal answer
B. Pausing at a line lets you inspect the entire state at once via the Variables/Stack panels, where prints show one value each and need a re-run to add more. A is irrelevant (it pauses, not speeds). C is false (print is useful, just narrower). D overstates it — a breakpoint reveals, it does not repair.
Q2 — The game runs and you want to confirm a specific enemy node actually exists and see its live position. Which tool?
A. The Output dock. B. The Remote scene tree, which shows the running game's live node tree and lets the Inspector read/edit a selected node's current properties. C. The FileSystem dock. D. The Project Settings dialog.
Reveal answer
B. The Remote tab mirrors the running game's tree; selecting a node shows its live properties, answering "is it in the tree?" and "what is its position now?" directly. A shows printed text, not live node state. C lists files on disk. D edits project configuration, not runtime state.
Q3 — You are editing enemy.tscn and want to test only it. Which key?
A. F5 — it runs whatever is open. B. F6 — run the current scene by itself. C. F8 — stop. D. Either; they are equivalent.
Reveal answer
B. F6 runs the current scene in isolation; F5 runs the project's main scene regardless of what is open (so A misstates it), and they are not equivalent (D). C stops a running game, it does not launch a scene.
Integration question¶
Q4 — open
Capstone, spanning the whole book. You press F5 and the game crashes with a "call on Nil" on a
line that reads an enemy's StatBlock to apply damage. Lay out a complete diagnosis using the
debugging tools of this chapter and the concepts from across Foundations — what you would observe in
the Debugger and Remote tree, which Part A and Part B ideas are candidate causes, and how the same
ideas would have prevented it. Conclude with why finishing this book means you can now work on the
ARPG and idle books rather than merely copy them.
Reveal expected answer
Observe first. The Debugger names the failing line and that the base is Nil, so the
StatBlock (or the enemy) reference is null; the stack trace shows how execution reached it.
Set a breakpoint before the line, re-run to the pause, and read the Variables panel to confirm
which reference is null rather than guessing; use the Remote tree to check whether the enemy
node is actually in the tree and whether its stats slot is populated. Candidate causes, by
concept: the StatBlock is a custom Resource (G1.6) — was it assigned in the Inspector, or is
the @export var stats slot empty? The reference may be a child grabbed without @onready (L2.2)
so it evaluated before the tree was built (G2.1 lifecycle); it may be a cast that returned null
without a guard (as, L2.1); the enemy itself may be an orphan never added to the tree (G1.2); or
a shared resource was .duplicate()d incorrectly so one path holds nothing (L1.5). Prevention,
same concepts: type the reference (var stats: StatBlock) so a wrong assignment is caught early
(L1.2); grab children with @onready (L2.2); guard casts with a null check (L2.1); assert(stats
!= null, ...) at the top of the function so the failure names the violated assumption at the
door, not three calls later (L2.4). Why you can now work on the game books: every layer of
that diagnosis — types and references (Part A), the node/scene/resource model and the lifecycle
(Part B), and the observability tools (this chapter) — is something you now reason about directly.
When the ARPG book builds a Health component or the idle book wires a tick autoload, you are not
copying steps; you know what each line is, why it is where it is, and how to find out when it
misbehaves. The hand-off table above is the proof: each thing those books assume has a home here,
and you have lived in all of them.