Seeing what a running game does
Why a game misbehaves: `game.debug.text()`, the F3 overlay, Build's Debugger.
Don't guess why a game misbehaves: ask it. Every engine game has game.debug, and its dump is written for you to read: a few
kilobytes of what is in the world, what moves, how long each system takes, and what looks wrong, each problem saying what to fix.
The full reference is the API reference's "The debugger" section (https://onceworlds.com/engine-api.md).
In a test or a headless run
import { simulate, dumpSimulation, simulationText } from '@onceworlds/engine/test';
const run = await simulate(config, { humans: 2, bots: 2, seconds: 60, profile: true });
console.log(simulationText(run)); // the run, then every page's world as text
if (run.failure) console.log(run.failure.error, run.failure.pages[0].dump); // the world at the frame it first broke
With a game you step yourself: game.step(120); console.log(game.debug.text()), or game.debug.dump() for the same as JSON.
dump({ focus: ['Hero', 1048581] }) always describes those entities; entities: 60 describes more; text({ max: 1500 }) fits
it in 1,500 characters, what is wrong first.
Read it in this order:
- problems: they break the game. Fix them first, in the order given.
- warnings: likely bugs (a body with no collider, things far away, a slow system, messages Net refused).
- worlds:
kindssays what exists and how many (a count that keeps growing is a leak: things spawned and never despawned);listshows the entities that matter with their place (pos), speed (vel), owner and their own components' values. - systems (with
profile: true): the slowest systems, in ms a frame. A frame at 60 fps has 16.7 ms for everything.
What the problems mean
| It says | Do |
|---|---|
X.y is NaN or Infinity on Hero #… |
Find what writes X.y: a division by zero, normalize of a zero vector, the square root of a negative number. |
World 'main' has … things to draw but no active Camera |
Spawn a camera: camera2D({ height: 12 }) in 2D, Camera({ projection: 'perspective' }) in 3D. |
Hero #… has Body2D, but the game has no Physics2D() |
Add the named module to createGame({ modules }). |
Body2D on Ball #… has no Collider2D |
Give the body (or a child) a collider, or it falls through everything. |
Nothing is called 'hero' / There is no sound called 'zap' |
Register the file: assets.add('hero', { type: 'image', url: 'hero.png' }), or use a name that exists. |
scenes: … a kind this engine doesn't know (or a component, a field) |
A scene file names something wrong: use the name the message suggests. |
… entities are over 10,000 units from the origin |
Something fell out of the world or flew off: despawn it, or stop what launches it. |
system 'x' in world 'main': … (×40) |
An error that keeps happening every frame: the message says where; fix it before anything else. |
System 'x' takes 6 ms a frame |
Make the loop cheaper: make queries once, keep entity.get() and allocations out of per-step loops. |
Make your own reasoning visible
Draw what the game is thinking (an AI's path, a hitbox, an aim line) instead of logging numbers. Lines show only while the overlay or Build's Debugger looks, so they can stay in the game:
game.debug.draw.path(bot.path, '#4ee1ff'); // from an update, late or render system
game.debug.draw.circle([x, y], attackRange, '#ff3b30');
game.debug.layer('hitboxes', (draw, world) => { /* draw every hitbox */ }); // a toggle in the overlay and in Build
In a browser
- F3 (or
`) shows the overlay: frame rate and a frame-time graph, the slowest systems, counts (entities, draw calls, bodies, contacts, network, sound voices, memory), pause, step one frame, slow motion, Pick (click something in the game to inspect it; numbers are editable) and Copy dump (the text above, to paste into a conversation). - physics in the overlay's Draw list shows every collider as the physics engine sees it: colliders that don't line up with what is drawn are the bug. nav (with the Navigation module) shows where agents can walk, the links between places, the obstacles and each agent's route: an agent that won't move has no route, or stands off the surface.
- Build's Debugger (the panel under the Game screen) shows the same for each player's game: the live tree of entities, the selected one's components, the profiler, and the errors. Click a node and the game outlines it.
Time
game.debug.paused = true, game.debug.step(1) (one fixed step) and game.debug.speed = 0.25 freeze, step and slow a game,
in a browser or a test. A bug that happens too fast to see happens slowly enough at 0.1.