Designing a Checkpoint System
Build checkpoint pads so players respawn at progress, not the start. Define Checkpoint and PlayerCheckpoint traits, update spawn on collision, only advance when checkpointId increases, and use onGameTick to respawn.
Script
Hello hello and welcome back to Jamango! Academy! In this episode, we’re building a checkpoint system that saves player progress as they move through your obby. If a player falls off the course, they’ll respawn at the last checkpoint they touched instead of going all the way back to spawn.
Part 1: Create checkpoint pads#
We’ll create a CheckpointTrait and attach it to Box Areas that act as checkpoint pads. Each checkpoint has a numeric checkpointId (0, 1, 2, …).
tsimport * as J from "jamango"; export const CheckpointTrait = J.defineTrait( "CheckpointTrait", J.schema.object({ checkpointId: J.schema.number(), }), { name: "Checkpoint", },
Place Box Areas where you want checkpoints, then use the wrench tool to attach the CheckpointTrait and set unique IDs (e.g. 0, then 1, etc.).
Part 2: Track player checkpoint state#
We’ll store per-player data using another trait that lives on the player entity. It contains a spawn position (Vec3) and the last playerCheckpointId reached.
tsexport const PlayerCheckpointTrait = J.defineTrait( "playerCheckpoint", J.schema.object({ spawn: J.schema.vec3(), playerCheckpointId: J.schema.number(), }), ); // Give new players the PlayerCheckpointTrait with defaults J.onPlayerJoin((playerId) => {
Part 3: Update checkpoint on collision#
Detect when a player touches a checkpoint. If they’re progressing forward (new ID is greater), update their respawn spawn and playerCheckpointId.
tsJ.onEntityCollisionStart( { source: [PlayerCheckpointTrait], target: [CheckpointTrait], }, (sourceId, targetId) => { const playerTrait = J.getTrait(sourceId, PlayerCheckpointTrait); const checkpointTrait = J.getTrait(targetId, CheckpointTrait); if (playerTrait.playerCheckpointId < checkpointTrait.checkpointId) {
Use checkpoints when respawning#
Replace the fixed spawn from the previous episode with the player’s saved spawn position.
tsJ.onGameTick(() => { const players = J.getAllPlayers(); for (const playerId of players) { const position = J.getEntityPosition(playerId); if (position[1] < -10) { const playerTrait = J.getTrait(playerId, PlayerCheckpointTrait); J.setEntityPosition(playerId, playerTrait.spawn); }
That’s it! Players now progress through your obby with checkpoints, and falling off returns them to their latest pad rather than the very start. Try building a course with at least three checkpoints and playtest the flow.