Zones and triggers
createZone defines an invisible sensor volume. When another entity’s collider intersects the zone, the engine tracks occupancy and invokes your enter, held, and exit callbacks. Zones do not render; they are ideal for goals, checkpoints, damage auras, and interaction prompts.
Minimal example
website/snippets/entities/zones-and-triggers.ts:
import { createZone } from '@zylem/game-lib/entity';
const goal = createZone({
name: 'goal-zone',
size: { x: 4, y: 2, z: 4 },
position: { x: 0, y: 1, z: 5 },
});
goal
.onEnter(({ visitor, globals }) => {
(globals as { inGoal?: boolean }).inGoal = true;
})
.onExit(({ visitor, globals }) => {
(globals as { inGoal?: boolean }).inGoal = false;
});
Callbacks
Register with fluent helpers or inline options:
| Callback | When | Context |
|---|---|---|
| onEnter | First frame of overlap | OnEnterParams |
| onHeld | Each frame while overlapping | OnHeldParams (heldTime accumulates) |
| onExit | Overlap ends | OnExitParams |
Each params object includes self (the zone), visitor (the other entity), and globals. Held callbacks also receive delta.
Zones use zoneCollision internally with static: true and sensor semantics so visitors keep their dynamic bodies.
Variations
- Size defaults to
{ x: 1, y: 1, z: 1 }; scale tall volumes for jump-through goals or flat pads for floor triggers. - Filter who can trigger via
collisionType/collisionFilteron the zone or visitor entities (Physics collisions). - For one-shot logic, gate
onHeldwithheldTimethresholds instead of polling distance inonUpdate.
Pitfalls
- Visitor identity — callbacks receive the concrete
GameEntityinstance; comparevisitor.options.nameor attach a tag incustomif you spawn many similar bodies. - Exit ordering — exits flush at the end of the collision pass; do not assume enter/exit pairs align with render frames when time scale changes.
- No mesh — zones are invisible in-game; use editor selection bounds or a debug box entity during level design if you need a visual guide.