Debug scatter command to prove navigation in the real scene #95

Closed
opened 2026-09-13 17:52:33 +01:00 by liamjd · 0 comments
Owner

Part of milestone #4. Depends on #80. Replaces #81.

Milestone #4 needs a proof that navigation works in the real game, not a control scheme. #81 proposed right-click move orders for that, but its own body conceded the point: direct move orders are not a shipping feature. Building the input arbitration, the selection highlight and a red-flash tween for a mechanic that gets deleted is a poor trade.

tools/probe_pawn_terrace.gd (#80) already settled the part that was genuinely in doubt — the pawn rides terraces rather than cutting through them, and A* routes over a one-level riser. What it deliberately does not exercise is everything above PawnView:

  • Pawns.move_to() — the facade that calls find_path(), flips state to MOVING and syncs cell/state from the view's signals. The probe calls view.follow() directly.
  • The real frame loop. The probe runs with set_process(false) and hand-stepped deltas.
  • The real scene: generated terrain rather than a hand-stamped staircase, several pawns at once, and Pawns as a parent that is not at the origin.
  • find_path() returning empty.

A debug scatter command covers all four for a fraction of the work, and builds nothing that has to be torn out later.

Design

  • A new input action, handled only while GameState.debug_mode is on, alongside the existing system_debug toggle in game.gd. No selection, no picker, no dependency on #78.
  • On press, every pawn whose state is IDLING gets Pawns.move_to(id, map.random_walkable_position(rng)). Pawns already moving are left alone, so the command is safe to spam.
  • random_walkable_position() draws from _main_region, so destinations are reachable by construction and the happy path is deterministic-ish. Unreachability is therefore not proven by this command; see below.
  • Print the outcome per pawn (id, from cell, to cell, whether move_to returned false) so a failure is legible without a UI.
  • Lives wherever the debug toggle lives rather than in PawnView, keeping the view ignorant of pathfinding — the same separation #81 called for and #75 will rely on.

Not in scope

  • Any player-facing move command. This is a debug affordance and should read as one.
  • Visual feedback for an unreachable destination. #81's red flash was UI for a mechanic that is not shipping. move_to() already returns false, and the print above is enough until something real needs to surface it.

AC

  • With debug mode on, pressing the action sends every idle pawn walking to a new destination; pressing it again mid-walk leaves moving pawns alone.
  • Nothing happens when debug mode is off.
  • Each pawn's state reads MOVING while walking and returns to IDLING on arrival, and its cell tracks the walk rather than updating only at the end — visible in the debug panel.
  • Several pawns move at once without interfering.
  • Headed check with a screenshot, which also serves as the check for #82 once that lands.

Note on unreachable destinations

random_walkable_position() only returns tiles on the main landmass, so this command cannot produce an empty path. The find_path()-returns-empty branch of Pawns.move_to() stays covered by unit tests only. That is a deliberate gap: forcing it in-game means either a separate island or a destination beyond destination_snap_radius, and neither is worth a bespoke debug affordance. Worth revisiting if #83 (re-path when a building cuts a path) makes blocked routes common.

Part of milestone #4. Depends on #80. Replaces #81. Milestone #4 needs a proof that navigation works **in the real game**, not a control scheme. #81 proposed right-click move orders for that, but its own body conceded the point: direct move orders are not a shipping feature. Building the input arbitration, the selection highlight and a red-flash tween for a mechanic that gets deleted is a poor trade. `tools/probe_pawn_terrace.gd` (#80) already settled the part that was genuinely in doubt — the pawn rides terraces rather than cutting through them, and A* routes over a one-level riser. What it deliberately does **not** exercise is everything above `PawnView`: - `Pawns.move_to()` — the facade that calls `find_path()`, flips `state` to `MOVING` and syncs `cell`/`state` from the view's signals. The probe calls `view.follow()` directly. - The real frame loop. The probe runs with `set_process(false)` and hand-stepped deltas. - The real scene: generated terrain rather than a hand-stamped staircase, several pawns at once, and `Pawns` as a parent that is not at the origin. - `find_path()` returning empty. A debug scatter command covers all four for a fraction of the work, and builds nothing that has to be torn out later. ## Design - A new input action, handled only while `GameState.debug_mode` is on, alongside the existing `system_debug` toggle in `game.gd`. No selection, no picker, no dependency on #78. - On press, every pawn whose state is `IDLING` gets `Pawns.move_to(id, map.random_walkable_position(rng))`. Pawns already moving are left alone, so the command is safe to spam. - `random_walkable_position()` draws from `_main_region`, so destinations are reachable by construction and the happy path is deterministic-ish. Unreachability is therefore **not** proven by this command; see below. - Print the outcome per pawn (`id`, from cell, to cell, whether `move_to` returned false) so a failure is legible without a UI. - Lives wherever the debug toggle lives rather than in `PawnView`, keeping the view ignorant of pathfinding — the same separation #81 called for and #75 will rely on. ## Not in scope - Any player-facing move command. This is a debug affordance and should read as one. - Visual feedback for an unreachable destination. #81's red flash was UI for a mechanic that is not shipping. `move_to()` already returns `false`, and the print above is enough until something real needs to surface it. ## AC - With debug mode on, pressing the action sends every idle pawn walking to a new destination; pressing it again mid-walk leaves moving pawns alone. - Nothing happens when debug mode is off. - Each pawn's `state` reads `MOVING` while walking and returns to `IDLING` on arrival, and its `cell` tracks the walk rather than updating only at the end — visible in the debug panel. - Several pawns move at once without interfering. - Headed check with a screenshot, which also serves as the check for #82 once that lands. ## Note on unreachable destinations `random_walkable_position()` only returns tiles on the main landmass, so this command cannot produce an empty path. The `find_path()`-returns-empty branch of `Pawns.move_to()` stays covered by unit tests only. That is a deliberate gap: forcing it in-game means either a separate island or a destination beyond `destination_snap_radius`, and neither is worth a bespoke debug affordance. Worth revisiting if #83 (re-path when a building cuts a path) makes blocked routes common.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
liamjd/UntitledColonyBuilder#95
No description provided.