Phaser AE

Visibility and line of sight

Free packv3.0.0-42DLogic

A set of wall segments and the three questions a game asks of them: what can be seen from here, can A see B, and what does a ray hit first. It is pure geometry on the CPU, cheap enough for AI to ask every step.

This is a Free pack. Every phaser.io account can use it in their games.

Released October 14, 2026 · updated October 20, 2026

Visibility and line of sight: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

The pack

visibility2d

function visibility2d(): Pack<{ visibility: Visibility2dApi }>

The 2D visibility pack: visibility polygons, line of sight and raycasts against wall segments. Headless, no columns, no passes — a factory for Visibility2d sets. The lighting pack uses the same class for its shadows.

Classes

Visibility2d

class Visibility2d

A set of wall segments and the queries on them: the VISIBILITY POLYGON from a point (rays to every segment corner ±ε, the nearest hit each, sorted by angle — the classic fan), line of sight between two points, and a raycast. Pure geometry, no kernel state: game.visibility.create() makes one; the lighting pack keeps one as game.lights.occluders.

  • readonly segments: Segment[] — The occluders. Add with addSegment/addRect/addPoly, or mutate a returned Segment to move a wall.
  • constructor(bounds?: { x: number; y: number; w: number; h: number }) — Optional starting bounds (see setBounds).
  • setBounds(x: number, y: number, w: number, h: number): void — A rectangle rays always stop at, so a polygon in an open world is finite. The lighting pack sets it to the camera's view each frame.
  • addSegment(x1: number, y1: number, x2: number, y2: number): Segment — Add one wall. Returns it, to move or to find and remove later.
  • addRect(x: number, y: number, w: number, h: number): void — Add the four walls of an axis-aligned rectangle (top-left x, y; width, height).
  • addPoly(points: ReadonlyArray<Vec2> | ReadonlyArray<number>, closed = true): void — Add a polyline's edges, as points or a flat [x, y, x, y…] list; closed (default true) joins the last point to the first.
  • remove(s: Segment): void — Remove one segment returned by addSegment; unknown segments are ignored.
  • clear(): void — Drop every segment (the bounds stay).
  • visibility(lx: number, ly: number, maxDist = Infinity): Vec2[] — The visibility polygon from (lx, ly): its vertices in angle order, ready to fan into triangles. maxDist caps the rays (a light's radius) and culls segments beyond it. Empty when nothing bounds the rays (no segments in reach, no bounds, no maxDist).
  • canSee(ax: number, ay: number, bx: number, by: number, maxDist = Infinity): boolean — True when the straight line from a to b crosses no segment (bounds ignored) and is within maxDist.
  • raycast(ox: number, oy: number, dirX: number, dirY: number, maxDist = Infinity): RayHit | null — The nearest segment (or bounds) hit by a ray from (ox, oy) along (dirX, dirY), within maxDist; null when nothing is hit.

Types

RayHit

interface RayHit

What raycast returns when the ray hits something.

  • x: number — Hit point x.
  • y: number — Hit point y.
  • dist: number — Distance from the origin along the ray.

Segment

interface Segment

One occluding wall segment, from (x1, y1) to (x2, y2). Mutate the fields to move it.

  • x1: number — Start x.
  • y1: number — Start y.
  • x2: number — End x.
  • y2: number — End y.

Vec2

interface Vec2

A point in world units.

  • x: number — x, world units.
  • y: number — y, world units.

Visibility2dApi

interface Visibility2dApi

game.visibility.

  • create(bounds?: { x: number; y: number; w: number; h: number }): Visibility2d — A fresh, empty occluder set. Not scene-scoped: the game holds it (drop it when the level ends).