Skip to content

Line

g.line(a, b) is a Bresenham line generator yielding every integer cell between two endpoints, inclusive of both. It’s the building block underneath g.line_of_sight and the natural primitive for projectile previews, path reveals, AI sight cones, and ranged-attack lines.

import { grid } from "@f0rbit/forge/grid";
const g = grid({ cols: 20, rows: 11, tile: 16 });
for (const cell of g.line({ x: 0, y: 0 }, { x: 4, y: 2 })) {
console.log(cell);
}
// → { x:0, y:0 } { x:1, y:1 } { x:2, y:1 } { x:3, y:2 } { x:4, y:2 }
type Grid = {
// ...
line: (a: Cell, b: Cell) => Generator<Cell>;
};
  • Yields every cell from a to b, inclusive of both endpoints.
  • Length is max(|dx|, |dy|) + 1.
  • Pure cell math — uses no Grid state at runtime, but lives on the Grid record for discoverability and consistency with g.line_of_sight / g.move_tile.
  • Symmetric in spirit (g.line(B, A) traces the same cells in reverse), modulo Bresenham tiebreaks on perfect diagonals.
import { grid } from "@f0rbit/forge/grid";
const g = grid({ cols: 20, rows: 11, tile: 16 });
const preview = (from: Cell, target: Cell, blockers: Set<number>): Cell[] => {
const cells: Cell[] = [];
for (const c of g.line(from, target)) {
if (blockers.has(g.key(c.x, c.y))) break;
cells.push(c);
}
return cells;
};

For symmetric FOV (radius-bounded, multi-target), prefer g.line_of_sight — it walks g.line() to every target cell within Chebyshev radius.

The standalone line export is removed. Build a tiny throwaway grid if you need bare line math without a real one:

// v0.2.0
import { line } from "@f0rbit/forge/grid";
for (const c of line(a, b)) { /* … */ }
// v0.3.0
import { grid } from "@f0rbit/forge/grid";
const g = grid({ cols: 64, rows: 64, tile: 1 });
for (const c of g.line(a, b)) { /* … */ }