Phaser AE

Tag collision rules

Free packv3.0.0-22DPhysics

Overlap rules by tag, with no dynamics: no gravity, no velocity, no mass. A rule names two tags and what happens when one of each touch, and that covers the pickups, bullets, triggers and simple wall sliding most 2D games need, without the cost of a physics simulation.

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

Released October 14, 2026 · updated October 19, 2026

Tag collision rules: 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

collision

function collision(): Pack<{ collide: CollideApi }, CollideTopics, { collide: CollideData }>

Overlap rules by tag and positional separation, with no dynamics. Runs after physics-2d when that is composed.

Constants

SHAPE

const SHAPE: { readonly circle: 0; readonly box: 1; }

Per-object: h.collide.shape (0 circle, 1 box — default box) and h.collide.radius (0 = from size).

Types

CollideApi

interface CollideApi

game.collide. Rules are scene-scoped: removed when the scene that made them exits.

  • on(tagA: string, tagB: string, cb: HitFn): void — Overlap callback for every (a, b) pair of tags, each fixed step, after simulation.
  • solid(tagA: string, tagB: string, opts?: { push?: 'a' | 'b' | 'both'; cb?: HitFn }): void — Keep A out of B by moving A (push: 'a', default), B, or both. Positional only — no velocity.
  • overlaps(h: Handle, tag?: string): Handle[] — Every live object overlapping h right now, optionally only those tagged tag.
  • raycast(x: number, y: number, dx: number, dy: number, maxDist: number, tag?: string): Hit | null — The nearest object along the ray within maxDist units, or null; tag limits the candidates. Tests bounding boxes (a circle as its square). Emits debug.ray.
  • test(a: Handle, b: Handle): boolean — Do these two overlap right now?
  • contact(a: Handle, b: Handle): Contact | null — WHICH SIDE of a is b on, and how deep — or null when they do not overlap. The side is the axis of minimum penetration, which is what a platformer's "am I standing on it" and a breakout's "which face did the ball hit" both actually ask. It honours wrap, so a pair straddling the seam measures as neighbours.
  • continuous: boolean — CONTINUOUS TESTING for the whole pack, live. Off by default. A discrete test asks "do these overlap NOW", and a thing that moves further in one step than the thing it should have hit is wide simply leaps over it: a bullet at 3000 units/s travels 50 units a step and a 10-unit wall is not there for any of them. With this on, a rule tests the object's whole PATH since the last step — the broadphase covers the sweep, and the pair is sampled along it — so the hit lands where it would have. It costs nothing for an object that did not move far: the sampling only kicks in when the motion is longer than the smaller of the two shapes. Sensible for bullets and never needed for walking speeds.

CollideData

interface CollideData

The collide columns every object carries.

  • shape: number — 0 circle, 1 box. Default 1.
  • radius: number — Circle radius, world units; 0 (default) means half the larger of the scaled width and height.

CollideTopics

interface CollideTopics

The signals this pack emits.

  • 'collision.hit': { a: string; b: string; rule: string } — One overlapping pair per rule per step (capacity 256): the two ids and the rule's name ("a×b" for on, "a⊥b" for solid).

Contact

interface Contact

Which side of a the contact is on and how deep it goes. The side is the axis of MINIMUM penetration, so pushing a out by overlap along it separates the pair — and 'bottom' is what "am I standing on it" means.

  • side: 'left' | 'right' | 'top' | 'bottom' — The side of a that b is against.
  • overlap: number — The penetration depth on that axis, world units.

Hit

interface Hit

A raycast result.

  • handle: Handle — The object hit.
  • x: number — Hit point x, world units (on the object's bounding box).
  • y: number — Hit point y, world units.
  • dist: number — Distance from the ray origin, world units.

HitFn

type HitFn = (a: Handle, b: Handle, contact: Contact) => void

A rule callback: (a, b) in the order the rule named its tags, plus the contact, read before any separation.