Dungeon Critters
Dungeon Critters spawns up to 80 animated critters on a canvas dungeon floor, each independently driven by a single shared FSM definition. It demonstrates createBehavioralFsm — define behavior once, pass a client object per call, and the FSM tracks state for every client separately via an internal WeakMap.
What It Demonstrates
Section titled “What It Demonstrates”createBehavioralFsmfor shared behavior — one FSM instance drives all 35–80 critters. No per-critter FSM instantiation.- Per-client state via
WeakMap— the FSM stores nothing on the critter object itself. State is an internal implementation detail, not a property you can accidentally overwrite. - The client object IS the context — every handler receives the critter as
ctx. Handlers readctx.x,ctx.y, writectx.vx,ctx.vy, record timestamps. The client is both the key and the working surface. - Multiple clients in different states simultaneously —
fsm.handle(critterA, "tick")andfsm.handle(critterB, "tick")resolve independently.fsm.currentState(critterA)may return"chase"whilefsm.currentState(critterB)returns"idle".
States
Section titled “States”| State | Color | Behavior |
|---|---|---|
idle | dim grey | Stationary; occasional random fidget; drifts back toward home territory if it strayed |
patrol | green | Moves toward a random waypoint within its home territory circle |
alert | amber | Stops and faces the player; blinking ! indicator; auto-disengages after 2.5s |
chase | red | Pursues the cursor at full speed; critter inflates visually |
flee | near-white | Runs away from the click point for 2s then returns to idle |
Key Pattern
Section titled “Key Pattern”One FSM definition, created once, drives every critter:
The game loop dispatches inputs across all critters each frame:
No timers in the FSM. With 50+ critters, independent setTimeout chains would be chaos. Instead, _onEnter stamps Date.now() on the client, and tick handlers compare elapsed time. One requestAnimationFrame loop drives everything.
FSM sets velocity; the game loop integrates position. Handlers write ctx.vx / ctx.vy (behavioral intent). The game loop applies x += vx and clamps to canvas bounds. FSM handlers stay focused on what the critter wants, not pixel math.
Interacting With the Demo
Section titled “Interacting With the Demo”- Move the cursor over critters to trigger detection and chase
- Click to blast critters within 80px — only chasing critters flee
- Click directly on a critter to select it and open the inspector panel
- Sensing range slider — adjust detection radius live for all critters
- Show sensing radius — toggle detection circle visualization
- Spawn — add 10 more critters (up to 80 max)