# Tilemap

> Talos 0.7 · Since 0.6

Present on `ctx.tilemap` when the entity has a `tilemap` component: a grid of tiles in the entity's XY plane.

Cells are counted from (0, 0) at the top-left, x along the entity's +X and y down its -Y. A tile is its index on the sheet (0 up, row by row), or -1 for an empty cell. `ts // Break the block the player head-butts, and open a door by clearing its column. const { x, y } = ctx.tilemap!.cellAt(hit.point) if (ctx.tilemap!.get("ground", x, y) === 3) ctx.tilemap!.set("ground", x, y, -1) for (let y = 4; y < 8; y++) ctx.tilemap!.set("ground", 12, y, ".") ```

## Signature

```ts
export interface Tilemap {
  /**
   * The tile at column `x`, row `y` of `layer`, or -1 for an empty cell; a cell outside the layer
   * reads as -1. A layer the tilemap does not have throws an `Error` whose `name` is
   * `TilemapLayerError`; a coordinate that is not a whole number, a `RangeError`.
   */
  get(layer: string, x: number, y: number): number
  /**
   * Sets the cell at column `x`, row `y` of `layer` to `tile`: a tile index (-1 empties it) or a
   * legend character (`"."` empties it). Its chunk is redrawn next frame; on a `collision` layer
   * the entity's body is rebuilt at once, so a cast straight after sees the change. Throws
   * `TilemapLayerError` for a layer it does not have, `RangeError` for a cell outside the layer or
   * a tile index not on the sheet, `TypeError` for a character not in the legend.
   */
  set(layer: string, x: number, y: number, tile: number | string): void
  /** The layers' names, in the component's order. */
  readonly layers: string[]
  /** A layer's size in cells. Throws `TilemapLayerError` for a layer it does not have. */
  size(layer: string): { width: number; height: number }
  /**
   * The cell a world point is over, through the entity's transform (whole numbers; negative or
   * past a layer's size when the point is off the map).
   */
  cellAt(point: Vec3): { x: number; y: number }
  /** The world point at the centre of cell (`x`, `y`), on the tilemap's plane. */
  cellCenter(x: number, y: number): Vec3
}
```

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

## Members

| Member | Signature | Description |
|---|---|---|
| `get` | `get(layer: string, x: number, y: number): number` | The tile at column `x`, row `y` of `layer`, or -1 for an empty cell; a cell outside the layer reads as -1. A layer the tilemap does not have throws an `Error` whose `name` is `TilemapLayerError`; a coordinate that is not a whole number, a `RangeError`. |
| `set` | `set(layer: string, x: number, y: number, tile: number \| string): void` | Sets the cell at column `x`, row `y` of `layer` to `tile`: a tile index (-1 empties it) or a legend character (`"."` empties it). Its chunk is redrawn next frame; on a `collision` layer the entity's body is rebuilt at once, so a cast straight after sees the change. Throws `TilemapLayerError` for a layer it does not have, `RangeError` for a cell outside the layer or a tile index not on the sheet, `TypeError` for a character not in the legend. |
| `layers` | `readonly layers: string[]` | The layers' names, in the component's order. |
| `size` | `size(layer: string): { width: number; height: number }` | A layer's size in cells. Throws `TilemapLayerError` for a layer it does not have. |
| `cellAt` | `cellAt(point: Vec3): { x: number; y: number }` | The cell a world point is over, through the entity's transform (whole numbers; negative or past a layer's size when the point is off the map). |
| `cellCenter` | `cellCenter(x: number, y: number): Vec3` | The world point at the centre of cell (`x`, `y`), on the tilemap's plane. |

## Example

The tested fixture `fixtures/app/agent.ts`.

```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
```
