Skip to content

Switch levels at runtime ​

Goal ​

The game has more than one level file. It starts on one and moves to the next when the player reaches the exit, unloading what the first placed and leaving what code spawned. Each level names the world it plays in.

Files you will edit ​

  • src/levels/index.ts
  • src/game.ts

Steps ​

  1. Keep every level file under src/levels/, and list them by name in src/levels/index.ts. main is src/level.json in the templates; the sandbox's edit mode lists what this file lists, and keeps it in step when a person adds a level there.
ts
import { validateLevel, type LevelFile } from 'gameable';
import mainDocument from '../level.json';
import caveDocument from './cave.json';

export const levels: Record<string, LevelFile> = {
  main: validateLevel(mainDocument),
  cave: validateLevel(caveDocument),
};

A level file may say where it plays: "place": "env.cave" at the top, the manifest id of a splat with its collider (src/assets.json). The page loads that place for the level the game starts on.

  1. Declare them in src/game.ts and switch with ctx.levels.load. Loading a level first destroys the loaded one's actors with reason levelUnload (their endPlay hears it) and leaves everything spawned from code.
ts
import { actors, defineGame, Door } from 'gameable';
import { levels } from './levels';

export default defineGame({
  levels,
  startLevel: 'main',
  systems: [
    (ctx) => {
      const exit = actors.named('exit');
      if (exit && exit.state.opened === true && ctx.levels.current === 'main') {
        ctx.levels.load(ctx, 'cave');
      }
    },
  ],
});

ctx.levels.names() lists the declared levels, ctx.levels.current the loaded one, ctx.levels.place() its world. The level a run starts on is startLevel, or the one {"level": "cave"} in the init options asks for: the template's page forwards ?level=cave from the address, which is how the sandbox opens a level for editing.

Verify ​

sh
npm test

Then npm run dev and open the page with ?level=cave: the game starts in the cave, in its own place. Open it without: it starts on main, and reaching the exit moves it to the cave, with the code-spawned things still there.

See also ​