Talos docs

RoadLine

Since 0.6Changed in 0.7

A road's centre line, from ctx.world.road(id).

Plain text

Read-only. Positions are in the road entity's own frame (add the entity's transform for the world's). The engine builds it once per road, so calling ctx.world.road(id) again is cheap and returns the same object; keeping it from init is still fine. @example const road = ctx.world.road("circuit")! const here = road.closest(ctx.entity.position, ctx.state.s) // lap progress, off-road distance const ahead = road.at(here.s + 20) // a point to steer toward if (Math.abs(here.offset) > ahead.halfWidth) ctx.hud.prompt("road.off") @example // Laps and race position, kept by the engine: no lap counter of your own. const me = road.progress(ctx.entity)! ctx.hud.set("lap", me.lap + 1) ctx.hud.set("place", me.place) if (me.lap >= 3) ctx.events.emit("finished", { place: me.place })

Signature

export interface RoadLine {
  /** Metres once around a closed road, end to end on an open one. */
  readonly length: number
  /** True for a loop (a lap circuit), false for an open road; `at` wraps on a closed road and clamps on an open one. */
  readonly closed: boolean
  /** Width of the kerb strip outside each edge, metres; 0 for a road with no `kerb`. `halfWidth` does not include it. */
  readonly kerbWidth: number
  /** Height of the kerb strip, metres; 0 with no `kerb`. */
  readonly kerbHeight: number
  /** The wall the file asked for, or null for a road with no `barrier`. */
  readonly barrier: RoadBarrier | null
  /** The road's trigger gates, in order along it: the child entity's scene id (`ctx.world.find(id)`) and its distance along the road. Gate 0 is the start line. */
  readonly gates: readonly { readonly id: string; readonly s: number }[]
  /** The centre line at distance `s`. */
  at(s: number): RoadSample
  /**
   * The nearest point on the centre line to `pos`. With `hintS` only samples within `windowM` (default
   * 40 m) of it are searched, so a car asking every tick cannot jump to a crossing section of road.
   */
  closest(pos: Vec3, hintS?: number, windowM?: number): RoadClosest
  /**
   * Where the kerb and the wall stand at distance `s`, as lateral distances from the centre line. The wall
   * is `halfWidth + kerbWidth + offsetM` out: keep a car's centre inside `barrier.inner` minus its radius
   * and it stays on the road side of it.
   */
  edge(s: number): RoadEdge
  /** The centre line as points `stepM` apart (default the road's sample step): a minimap polyline. */
  polyline(stepM?: number): Vec3[]
  /**
   * How far `entity` (a handle or scene id) has come along this road, lap by lap; null when it is not
   * alive. The first call starts tracking it on this road, where it is now; from then on the engine
   * steps it every tick (after physics, before behaviours), so every behaviour reads the same answer
   * in a tick and a rival nobody asks about still has a place. There is no other call to start or
   * stop it: a despawned entity leaves the standings by itself.
   *
   * Laps count at checkpoints: the road's gates in order (gate 0 is the start line), or every quarter
   * of a road with no gates. Reversing over a checkpoint takes it back, and one skipped (a cut across
   * the infield, a teleport past it) has to be crossed before any after it counts, so neither earns a
   * lap. An entity first seen in the last quarter of the lap before the line is on the grid: crossing
   * the line starts its first lap. Forward is the way `s` grows.
   */
  progress(entity: EntityHandle | string): RoadProgress | null
  /** The entities tracked on this road (see {@link RoadLine.progress}), in race order: 1st first. */
  standings(): RoadStanding[]
}

Import: import type { RoadLine } from "@argus/api"

Members

MemberSignatureDescription
lengthreadonly length: numberMetres once around a closed road, end to end on an open one.
closedreadonly closed: booleanTrue for a loop (a lap circuit), false for an open road; at wraps on a closed road and clamps on an open one.
kerbWidthreadonly kerbWidth: numberWidth of the kerb strip outside each edge, metres; 0 for a road with no kerb. halfWidth does not include it.
kerbHeightreadonly kerbHeight: numberHeight of the kerb strip, metres; 0 with no kerb.
barrierreadonly barrier: RoadBarrier | nullThe wall the file asked for, or null for a road with no barrier.
gatesreadonly gates: readonly { readonly id: string; readonly s: number }[]The road's trigger gates, in order along it: the child entity's scene id (ctx.world.find(id)) and its distance along the road. Gate 0 is the start line.
atat(s: number): RoadSampleThe centre line at distance s.
closestclosest(pos: Vec3, hintS?: number, windowM?: number): RoadClosestThe nearest point on the centre line to pos. With hintS only samples within windowM (default 40 m) of it are searched, so a car asking every tick cannot jump to a crossing section of road.
edgeedge(s: number): RoadEdgeWhere the kerb and the wall stand at distance s, as lateral distances from the centre line. The wall is halfWidth + kerbWidth + offsetM out: keep a car's centre inside barrier.inner minus its radius and it stays on the road side of it.
polylinepolyline(stepM?: number): Vec3[]The centre line as points stepM apart (default the road's sample step): a minimap polyline.
progressprogress(entity: EntityHandle | string): RoadProgress | nullHow far entity (a handle or scene id) has come along this road, lap by lap; null when it is not alive. The first call starts tracking it on this road, where it is now; from then on the engine steps it every tick (after physics, before behaviours), so every behaviour reads the same answer in a tick and a rival nobody asks about still has a place. There is no other call to start or stop it: a despawned entity leaves the standings by itself. Laps count at checkpoints: the road's gates in order (gate 0 is the start line), or every quarter of a road with no gates. Reversing over a checkpoint takes it back, and one skipped (a cut across the infield, a teleport past it) has to be crossed before any after it counts, so neither earns a lap. An entity first seen in the last quarter of the lap before the line is on the grid: crossing the line starts its first lap. Forward is the way s grows.
standingsstandings(): RoadStanding[]The entities tracked on this road (see {@link RoadLine.progress}), in race order: 1st first.

Example

The tested fixture fixtures/app/agent.ts.

import type { Behavior } from "@argus/api"

// Sends a nav agent to `props.target` once, then reports arrival through ctx.state so the
// test can read it without polling the crowd directly.
export default {
  init(ctx) {
    ctx.state.arrived = false
    ctx.nav?.goTo(ctx.props.target as [number, number, number])
  },
  update(ctx) {
    if (ctx.nav?.arrived) ctx.state.arrived = true
  },
} satisfies Behavior