| name | godot-game-loop-time-trial |
| description | Expert patterns for racing mechanics, checkpoint tracking, and ghost recording/playback in Godot 4. Use when building racing games, speed-run platformers, or arcade trials. |
Architectural Thinking: The "Validation-Chain" Pattern
A Master implementation treats Time Trials as a State-Validated Sequence. Recording a time is easy; ensuring the player didn't cheat via shortcuts requires a strictly ordered CheckpointManager.
Core Responsibilities
- TimeTrialManager: The central clock. Validates checkpoint order and handles "Best Lap" logic.
- GhostRecorder: Captures high-frequency transform data. Uses delta-time timestamps for frame-independent playback.
- Checkpoint: Spatial triggers that notify the Manager.
Expert Code Patterns
1. Robust Checkpoint Validation
Prevent "Shortcut Cheating" by requiring checkpoints to be cleared in numerical order.
Wire Area body_entered (physics) โ TimeTrialManager.pass_checkpoint(index). The manager owns usec timing โ see script.
2. Space-Efficient Ghosting
Sample at a fixed rate (e.g. 10 Hz). Lerp position; slerp Quaternion rotation (ghost_recorder.gd / ghost_replayer.gd). Never Euler-lerp ghost heading.
Master Decision Matrix: Data Storage
| Format | Best For | Implementation |
|---|
| Dictionary Array | Prototyping | Simple [{t: 0.1, p: pos}, ...] |
| Typed Array | Performance | PackedVector3Array for positions. |
| JSON/Binary | Saving | FileAccess.get_var() to save ghost files. |
NEVER Do
- NEVER use OS.get_ticks_msec() for ultra-precise race timing โ Millisecond resolution is too coarse for high-end racing games. Use
Time.get_ticks_usec() for microsecond precision.
- NEVER rely exclusively on _process() for finish line triggers โ Visual frames can skip during lag. Always evaluate physical overlaps in
_physics_process() to guarantee detection within the fixed physics step.
- NEVER evaluate Area3D overlaps immediately after instantiation โ The physics server requires at least one physics frame to synchronize.
await get_tree().physics_frame before checking for players.
- NEVER scale a CollisionShape3D on a checkpoint non-uniformly โ This breaks the underlying SAT collision math. Always scale the internal shape resource (e.g.,
BoxShape3D.size) instead.
- NEVER use TCP (reliable) for syncing positions in multiplayer racing โ Congestion algorithms cause huge spikes. Use
ENetMultiplayerPeer with TRANSFER_MODE_UNRELIABLE for high-frequency position updates.
- NEVER trust client-side finish line/lap crossing โ Always validate triggers on the authoritative server using
multiplayer.is_server() to prevent cheating.
- NEVER use standard float equality (==) for record lap times โ Use
is_equal_approx() to account for precision loss in accumulated time variables.
- NEVER hardcode input checks without flushing the buffer โ For frame-perfect boost/stop responses, call
Input.flush_buffered_events() to ensure the engine has processed the latest raw input.
- NEVER allocate new Vector3 arrays inside fast path-following loops โ This triggers the garbage collector. Use
PackedVector3Array to maintain a contiguous memory block.
- NEVER use dynamic string paths ($"../Checkpoint") in tight loops โ Lookups are slow. Use
@onready to cache node references during initialization.
- NEVER record the whole player object for ghosts โ Only record core transforms (position/rotation). Recording the whole object is memory-intensive and unnecessary for visual ghosts.
- NEVER give the ghost collision โ It should be a purely visual indicator (e.g., semi-transparent) to avoid disrupting the player's line.
- NEVER neglect checkpoint sequencing โ Don't just check if the player hit the finish line. Verify they passed every intermediate checkpoint in the correct order.
Available Scripts
MANDATORY: Follow the golden path order. Read each listed script before coding that stage.
Golden path (MANDATORY)
time_trial_manager.gd โ microsecond (Time.get_ticks_usec) or physics-frame clock; pass_checkpoint only from physics overlaps / Area signals
- Checkpoint Areas โ ordered indices into the manager (physics frame, not
_process)
ghost_recorder.gd โ samples {t, p, q} with Quaternion rotation
ghost_replayer.gd โ position lerp + Quaternion slerp (never Euler lerp)
time_trial_leaderboard_bridge.gd โ integer usec/msec โ UI strings
Script index
10 Expert patterns: Microsecond timing, server-authoritative validation, rubber-banding AI, and frame-perfect input flushing.
Central clock. Accumulates Time.get_ticks_usec() (or physics-frame counts). Finish checks must come from physics overlaps.
Captures transform samples with Quaternion "q" fields for slerp-safe playback.
MANDATORY with recorder. Replays samples via position lerp + Quaternion.slerp.
Jitter-buffer for smooth ghost playback during network streaming.
Formatting utility for converting raw time data to human-readable strings.
Expert Time Trial Patterns
1. Delta-Compression for Ghosts
Store a keyframe only when position/rotation changes beyond a threshold. Persist with FileAccess.open_compressed() + ZSTD; prefer binary floats over JSON.
2. The Leaderboard Bridge
Store records as int usec/msec. Format with %02d:%02d.%03d for stable UI (e.g. 01:24.450).
Expert knowledge (on demand)
LLM-ignorance rule: If a general agent would not know it before reading, load the reference โ never delete expert deltas.
Reference
Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain โ do not preload the whole lattice.
Official Documentation
- Time โ
get_ticks_usec() for microsecond lap clocks when OS.get_ticks_msec() is too coarse for race records.
- Idle and Physics Processing โ why finish-line and checkpoint overlap must run in
_physics_process, not visual _process frames that can skip under load.
- Area3D โ monitoring, collision masks, and
body_entered for ordered checkpoint gates without scanning every physics body.
- Collision shapes (3D) โ scale shape resources (
BoxShape3D.size) instead of non-uniform CollisionShape3D scale so SAT stays valid on gates.
- Using transforms โ global position/basis capture for ghost samples and why Euler-only storage needs careful replay conversion.
- Quaternion โ
slerp() between keyframes so ghost heading avoids gimbal lock from naive Euler lerp.
- Transform3D โ
interpolate_with() for jitter-buffered network ghost playback between ordered frames.
- Saving games โ
FileAccess / store_var patterns for persisting ghost runs and best-time dictionaries without float display round-trips.
- High-level multiplayer โ server-authoritative RPC validation so clients cannot fake lap/finish crossings.
- MultiplayerPeer โ
TRANSFER_MODE_UNRELIABLE for high-frequency racer transforms where TCP-style reliability spikes latency.
- Input โ
flush_buffered_events() when frame-perfect boost/stop must see the latest raw input before the physics step.
- Engine โ
physics_ticks_per_second / for integer frame-count timing bridges into MM:SS.mmm UI.
Related Skills
Prerequisites
- godot-project-foundations โ scene tree, autoloads, and resource layout before wiring a
TimeTrialManager and checkpoint Areas into a track scene.
- godot-physics-3d โ Area3D/CollisionShape3D layers, RigidBody/CharacterBody vehicles, and physics-frame overlap rules that make checkpoint sequencing trustworthy.
- godot-signal-architecture โ typed lap/split/finish signals between gates, manager, HUD, and ghost systems without brittle node-path coupling.
- godot-gdscript-mastery โ typed arrays, Packed* buffers,
await physics_frame, and RPC annotations used in timing and authority patterns.
Complements
- godot-input-handling โ action maps and buffered boost/steer input that time-trial NEVER rules require to flush before physics.
- godot-save-load-systems โ compressed binary ghost files and best-time persistence beyond in-memory sample arrays.
- godot-multiplayer-networking โ ENet peers, authority, and unreliable transform sync for live races and streamed ghost frames.
- godot-adapt-single-to-multiplayer โ lag compensation, snapshots, and interest patterns when elevating a solo time trial into online racing.
- godot-navigation-pathfinding โ NavigationServer3D agent max-speed for rubber-band AI that paces against the player without cheating collision.
- godot-monte-carlo-balancer โ simulate rubber-band factors, checkpoint difficulty, and target clear times before shipping trial parameters.
- godot-camera-systems โ chase/replay cameras that must track live cars and non-colliding ghost visuals during playback.
Downstream / consumers
- godot-genre-racing โ full racing genre stack that consumes checkpoint clocks, ghosts, and leaderboard formatting as core loop primitives.
- godot-game-loop-collection โ meta inventory/collection loops that can gate unlocks on validated best times from this skill.
Master
- godot-master โ library router and mirrored module entry for cross-skill discovery.