Skip to content

Run a match with a game mode ​

Goal ​

Copy templates/blank. A deathmatch to 5 kills with a 3-minute limit, respawns after 2 seconds, and a scoreboard in the HUD. No match code of your own.

Files you will edit ​

  • src/game.ts
  • src/level.json

Steps ​

  1. Put a GameMode and two PlayerStarts in src/level.json. The mode's props are the rules; every one has a default.
json
{
  "format": 1,
  "actors": [
    {
      "class": "GameMode",
      "position": [0, 0, 0],
      "props": { "scoreToWin": 5, "matchTime": 180, "respawnDelay": 2 }
    },
    { "class": "PlayerStart", "position": [-6, 1, 0] },
    { "class": "PlayerStart", "position": [6, 1, 0], "yaw": 180 }
  ]
}
  1. In src/game.ts, spawn players at the starts, hurt with applyDamage (the shooter's controller as instigator gets the kill), and show matchSummary() in your HUD.
ts
import { applyDamage, defineGame, matchSummary, playerControllerOf, prefab } from 'gameable';
import type { GameContext } from 'gameable';
import level from './level.json';

const Hero = prefab({ name: 'hero', health: 100 });

/** Call from your weapon when a shot lands: the shooter's seat gets the kill. */
export function hit(ctx: GameContext, targetBody: number, shooterSeat: number): void {
  applyDamage(ctx, targetBody, 25, { instigator: playerControllerOf(shooterSeat) ?? undefined });
}

export default defineGame({
  level,
  player: { prefab: Hero, spawn: 'playerStart' },
  systems: [
    (ctx) => {
      ctx.hud.set({ match: matchSummary() });
    },
  ],
});
  1. To change one rule, derive a mode and use its class name in the level:
ts
import { defineGameMode, GameMode } from 'gameable';

defineGameMode('LastOneStanding', {
  props: { ...GameMode.spec.props, respawnDelay: -1 },
  onPlayerDied(self, victim, killer, ctx) {
    // e.g. end when one seat is left: endMatch(ctx, [survivorSeat])
  },
});

Verify ​

matchSummary().state goes waitingToStart → inProgress → waitingPostMatch, and the winner's score reaches 5.

See also ​