The pack
gridWalker
function gridWalker(): Pack<{ gridWalker: GridWalkerApi }>
The grid-walker pack: game.gridWalker, the pure grid walker. It needs no world; a rules pack imports createGridWalker instead. No options.
Helpers
createGridWalker
function createGridWalker(config: GridWalkerConfig)
Create a headless continuous walker in tile units; wall and portal policies belong to the caller. Throws on an invalid config (see GridWalkerConfig).
Classes
GridWalker
class GridWalker
Continuous buffered tile movement with exact centre handling and immediate reversals.
readonly config: GridWalkerConfig— The configuration the walker was created with.constructor(cfg: GridWalkerConfig)get state()— A copy of the current pose; changing the copy does nothing to the walker.want(d: GridDirection)— Buffers the heading to take at the next junction where that turn is open; a full reversal happens at once. Throws if the direction is not up, left, down or right.place(at: GridPoint, direction = this.s.direction)— Moves the walker toat(finite tile coordinates) facingdirection, default the current heading, and clears any buffered turn and corner alignment. Throws on non-finite coordinates or an invalid direction.tick( dt: number, speed = this.config.speed, onCentre?: (p: GridPoint, d: GridDirection) => GridDirection, onEnter?: (p: GridPoint, d: GridDirection) => void, onTravel?: (part: GridTravel) => void, )— Advancesdtseconds atspeedtiles/s (defaultconfig.speed) and returns the new state. Movement is split into pieces of at most 1/64 tile and stops exactly at tile centres, so a large frame never skips a decision: -onCentre(cell, heading)runs each time the walker sits exactly on a tile centre (not while sliding onto a lane), including every tick it waits there against a wall, and returns the heading to want next, aswant()would; a ghost's brain picks its turn here. -onEnter(cell, heading)runs when the walker's rounded tile changes, or it arrives through a portal: one tile ahead of its next centre, which is when the arcade ghosts look ahead. -onTravel(part)reports every piece of the trajectory with its time window in the tick, including the stationary remainder after a wall stop; a portal is a zero-lengthportalpiece, never a sweep. Throws whendtis outside 0..10 s,speedoutside 0..10000 tiles/s, or a tick would take over a million pieces.snapshot()— A copy of the current state, to save; the same asstate.restore(state: GridWalkerState)— Replaces the state with a saved one fromsnapshot(). Throws if a direction is invalid, x, y or line is not finite, or align is not "x", "y" or null.
Types
GridDirection
type GridDirection = "up" | "left" | "down" | "right"
Renderer-independent lane movement. Coordinates are tile centres: integers, one tile = 1 unit.
GridPoint
interface GridPoint
Tile-centre coordinates; one tile is one model unit.
x: number— Column position in tiles; tile centres are integers and x grows to the right.y: number— Row position in tiles; tile centres are integers and y grows downwards, so "up" is -1.
GridTravel
interface GridTravel
One part of a tick's trajectory. Times are fractions of the tick in [0, 1]. Portal segments have equal start/end times and represent discontinuities, never travel through intervening space.
from: GridPoint— Where this part of the trajectory starts, in tiles.to: GridPoint— Where this part of the trajectory ends, in tiles; for a portal it is the arrival point.start: number— When the part starts, as a fraction of the tick from 0 to 1.end: number— When the part ends, as a fraction of the tick from 0 to 1; equal tostartfor a portal.kind: "move" | "portal"—movefor travel through space,portalfor a jump that crosses no intervening tiles.
GridWalkerApi
interface GridWalkerApi
What the grid-walker pack adds to a game: game.gridWalker.
create: typeof createGridWalker— Make a walker (seecreateGridWalker).
GridWalkerConfig
interface GridWalkerConfig
Movement speed, blocking predicate, corner windows and optional directed portals.
at: GridPoint— Starting position in tiles; both coordinates must be finite. Tile centres are integers.direction?: GridDirection— Starting heading; defaultleft. Throws if it is not up, left, down or right.speed: number— Tiles per second; finite and not negative. Throws otherwise.walls: (x: number, y: number) => boolean— Whether tile (x, y), in integer tile coordinates, blocks movement. Asked for tiles outside any board too, so it must answer for them.turnBefore?: number— How far before a tile centre, in tiles, a wanted turn may still be taken; 0 to under 0.5, default 0. Throws outside that range.turnAfter?: number— How far past a tile centre, in tiles, a wanted turn may still be taken; 0 to under 0.5, default 0. Throws outside that range.arcadeAsymmetry?: boolean— When true, the before and after windows swap for headings that move up or left, reproducing the arcade original's lopsided cornering; default false.portal?: (at: GridPoint, direction: GridDirection) => GridPoint | null— Directed portal lookup: the tile an actor leavingatindirectionarrives at, or null.portalAt?: "centre" | "edge"— Where a portal fires.centre(default) jumps from the source tile's centre to the destination's centre.edgewalks on to the source tile's outer edge, jumps to the matching edge of the destination tile and carries the remaining distance on, so a wrap tunnel slides off one side and in from the other without skipping a tile or needing walkable cells beyond the board. The cell beyond the source edge is never tested.
GridWalkerState
interface GridWalkerState extends GridPoint
Current continuous pose, buffered heading and residual diagonal corner alignment.
direction: GridDirection— The heading it is travelling in now.wanted: GridDirection— The buffered heading it takes at the next junction where that turn is open; equal todirectionwhen no turn is waiting.align: "x" | "y" | null— The axis it is still sliding onto a lane along after a corner turned off-centre, or null when it is on a lane.line: number— The lane coordinate in tiles thatalignslides to; 0 whilealignis null.


