Collision — overlap detection

collision reports when targets' bounds overlap. It runs in the stage's Detect phase, reads targets' shapes, and emits events — it does not decide what a collision means. Detection is a pure, deterministic function of this frame's positions; the response (bounce, stop, score) is a script's job. Detect and report; let policy live above.

Status: design. Not built yet.


What it is

collision is the interactive sibling of motion and tween: once things move, you want to know when they touch. Each tick, after motion and tween have written positions in Advance, collision runs in Detect — it reads the enrolled targets' bounds, finds which pairs overlap, and emits an event for each. That is all it does, and the whole point is that it stops there.


Detection is deterministic; response is not

This split is the load-bearing decision, and it's why collision stays clean where physics engines get messy:

  • Detection is a pure function of positions — "do these two bounds overlap on this frame?" is exact AABB / circle maths on the settled Advance-phase positions. Deterministic, frame-order-independent, replayable.
  • Response is where determinism dies — "bounce," "push apart," "resolve penetration" is iterative, order-sensitive, and frame-rate-dependent in the general case; it is the tar pit that makes physics engines non-deterministic.

So collision detects and reports; it never moves anything. What happens on a collision is ordinary AntBASIC / Luau — stop the motion, start a tween, play a sound, add a point. Mechanism in the core, policy in scripts. (A small set of canned, deterministic responses — stop-on-contact, reflect — can be offered as convenience, but they are opt-in and pure; anything iterative stays out until you deliberately add a physics layer, below.)


Bounds and layers

A target enrolled for collision carries a bound — an AABB (axis-aligned box) or a circle, the two shapes whose overlap test is cheap and exact. Testing every pair against every other is N²; two things keep it cheap and controlled:

  • A broad phase — a spatial partition (grid, or sort-and-sweep) narrows the candidate pairs before the exact test, so a crowded scene stays fast.
  • Layers and masks — each target sits on a layer and tests only against a mask of layers. Players test walls and pickups, not each other; bullets test enemies, not other bullets. This is both a performance lever and how you express what should interact.

Events — enter, stay, exit

Collision events across ticks

collision compares this frame's overlapping set with last frame's and emits three kinds of event, so a handler reacts to transitions, not just steady state:

  • enter — a pair began overlapping this tick (the hit);
  • stay — a pair still overlaps (ongoing contact);
  • exit — a pair stopped overlapping (separation).

Events are raised in Detect and delivered in React (per the stage's rule), in a defined order, so handling a collision never perturbs the frame that produced it — and the same inputs replay the same events.


Queries

Detection runs continuously; sometimes you want to ask directly:

  • overlapping(a, b) — do these two overlap right now (a boolean, for a script that would rather test than subscribe);
  • at(x, y) / query(shape) — which targets are under a point or inside a region — hit-testing, picking, area-of-effect.

Queries read the same bounds as detection, so they agree with it exactly.


Response stays in scripts — and physics is a later, opt-in choice

To be explicit about the ladder: today collision is detect + emit + query, and every response is script policy. If you later want simulated physics — momentum, restitution, stacking — that is a separate, opt-in physics layer with its own deterministic fixed-step integrator, in its own stage phase between Detect and React. It is deliberately not baked into collision, so the common case (arcade-style "did I hit it? then do this") stays pure and simple, and the heavyweight case is something you choose, never something you inherit.


On the stage

collision is a stage sibling: it runs in Detect, reads target bounds (written by motion / tween in the preceding Advance), emits events, and references no other system. It inherits the determinism contract: detection is pure, delivery is ordered, so a whole interactive scene replays identically.


Clients

  • AntBASIC — TOUCHING(a%, b%) is the immediate-test front door, and an ON COLLISION a%, b% … handler subscribes to the enter event — collision as a beginner can reach it.
  • Luau — require("collision"): watch / on / overlapping / at for tools, games, and apps.

Related

  • motion · tween — the movement siblings · stage — the substrate (phase order, events) · physics — the opt-in simulation layer (future)
  • luau_collision — the Luau API · AntBASIC — the TOUCHING / ON COLLISION front door

Important: The Ant64 family of home computers are at early design/prototype stage, everything you see here is subject to change.