Skip to content

Tell a playtest what happened ​

Goal ​

A playtest — a person recording a run, or the page's agent playing the game — knows where the player died and why, where the goal is, and when the game is won. The engine already notices falls, respawns, stuck players and missed jumps on its own; this adds what only the game knows, so the agent can learn to seek the goal and the reports can say "eight deaths at the second gap: lava".

Files you will edit ​

  • src/game.ts
  • src/systems/hazards.ts

Steps ​

  1. Say where the goal is when the level starts, and again when it moves on.

    diff
    // src/game.ts
    -import { defineGame } from 'gameable';
    +import { defineGame, playtest } from 'gameable';
    
     export default defineGame({
       // ...
       init(ctx) {
    +    playtest.goal({ x: 0, y: 12, z: -40 });
       },
     });
  2. Mark the death, with its cause, where the game kills the player, and the win where it is won.

    diff
    // src/systems/hazards.ts
    +import { playtest } from 'gameable';
    
     export function hazards(ctx: GameContext): void {
       if (touchingLava(ctx)) {
    +    playtest.death('lava');
         respawn(ctx);
       }
       if (reachedFlag(ctx)) {
    +    playtest.win('flag');
         ctx.hud.set({ message: 'YOU WIN' });
       }
     }

    A pickup is playtest.reward(1, 'coin'), a hit playtest.damage(10, 'spikes'), a checkpoint playtest.checkpoint(). None of them changes the game, and none allocates, so they stay in the shipped game.

    Say what kills on any touch when you spawn it: playtest.hazard(spike) for a bed of spikes, playtest.hazard(ghost) for an enemy that cannot be stomped. The playtest's route goes around a hazard, or jumps it when there is no way round, and the route pilot jumps one in its way. Leave out an enemy the player beats by landing on it: the pilot stomps it, and avoiding it makes the pilot worse. A moving hazard's body is followed, and when the entity is gone so is the hazard. A hazard with no body takes its place: playtest.hazard(lava, 2, { x: 4, y: 0, z: -10 }).

    The goal is what the agent steers by: with it, the engine scans the level from above when a run starts and plans a route there, walking and jumping, and the agent follows the route's next waypoint instead of a straight line at the flag. When the goal cannot be reached with the jumps players make, the playtest's findings say where the gap is.

    A checkpoint also tells the playtest agent where to start its next life: after a death, a fall or a timeout the engine puts the player back at the last checkpoint it reached (or the run's start, with none), so a long level is tested past its first hazard.

Verify ​

sh
npm run dev

In the browser console, __gameable.playtest.on((n) => console.log(n)), then walk into the lava: an event notice with kind: 'death' and note: 'lava' arrives. __gameable.playtest.summary().findings lists what a run found.

See also ​

  • packages/sdk/README.md — the playtest facade
  • packages/wasm-host/README.md — playtests, the agent and traces
  • Write a game system