Kart race

A complete kart race: grid, countdown, ordered laps and checkpoints, drift mini-turbos, boost pads, item crates, bot rivals, standings and hooks to change any rule.

Source: module-kits:kits/race_kart/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs race-kartMCP tool: gripforge_docs { "topic": "race-kart" }

Kart races with laps, drifts and items (race.kart) #

What it is for #

race.kart runs a kart race on a circuit: a start grid, a countdown, the racers (the first is the player, the others are bots), ordered progress along the track with checkpoints and laps, drift charge with two mini-turbo tiers, boost pads, item crates (boost, shield, pulse), a recover that returns a kart to its last checkpoint for a time penalty, standings and a final result. The karts are vehicles of vehicle.drive; the circuit comes from world.racetrack. The kit holds the race rules and wires them; the presentation (HUD, start screen, drivers, sounds) is shipped with the kit.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "race.kart" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "race.kart",
                              config: { "racers": 6, "countdown": 3, "difficulty": "normal" } }

It requires world.racetrack, vehicle.drive (with handling: kart), input.actions, spawn.entities, physics.port and game.engine, and conflicts with character.third_person and character.platformer. The circuit is data of the project (race_tracks, owned by world.racetrack: width, laps, points, boostPads, crates). Default controls: W A S D or the arrows drive, Space drifts, Shift boosts, E uses the item (action race.item), R returns to the track (action race.reset); gamepad and touch share the same actions.

First example #

<!-- test: kits/game_engine/host/tests/parity.rs::rust_host_matches_the_typescript_traces --> The test replays the fixture race.kart.race: a circuit ring of width 12 with two laps, four racers (driverNames: ["Ace", "Bo"]) and a 0.5 s countdown. It calls the services, presses the keys and checks every frame:

  1. race.laps.playerVehicle() answers the entity of the player's kart; race.laps.standings() answers the table.
  2. resetToTrack() and the key R return the kart to its last checkpoint (race.respawn, with a penalty).
  3. E uses the held item (race.item), W and a steering axis drive, and the standings are read again until the finish (race.finished).

Settings and defaults #

SettingTypeDefaultMeaning
racersinteger (1..8)6number of karts; the first is the player
countdownnumber (0..5)3seconds before the start
difficultyeasy, normal, hardnormalbot target speed times bots.skill
itemsbooleantruecrates and items
driverNameslist of strings[]names that replace the default ones (You, Nova, Mako, Pip, Tess, Sol, Ash, Rue)
cameradistance, height8.5, 4chase camera, metres
gridstart, spacing, lane, spawnStart, spawnSpacing5, 5, 2.1, 0.01, 0.008first row behind the line, row gap, column offset (m); first spawn in track fractions
progresssee belowlaps, recovery and road edge
driftsee belowdrift charge and mini-turbo
boostpad, padRadius, minTank1.4, 3, 30pad boost seconds, pad half-length (m), tank floor while boosting
itemRulessee belowitems and crates
botssee belowbot driving
  • progress: checkpoints 16 per lap; recoverPenalty 2 s; travelMin 2, travelFactor 3, travelSlack 1 (accepted travel per tick, so teleports and infield cuts never award laps); lateralSlack 2; edgeInset 0.9 and edgeDamping 0.94 (karts are held inside the road edge); offTrack 15 and fallY -3 (beyond these a kart recovers); stuckSpeed 1 and stuckSeconds 4 (a stuck bot recovers).
  • drift: minSlip 0.18, minSpeed 8, resetSpeed 7, maxCharge 2.4, tier1 0.65, tier2 1.6, boost1 1.15, boost2 2.1. Releasing with a charge of at least tier1 gives boost1 seconds of boost; at least tier2 gives boost2.
  • itemRules: boost 2.5 and shield 6 (seconds), pulseTime 0.5, pulseRadius 15, slowTime 1.5, slowDamping 2, slowThrottle 0.1, crateRadius 3, crateRespawn 3, crateHeight 0.9, crateLanes 0.29, botUseEvery 5.
  • bots: lookahead 8, lookaheadPerSpeed 0.5, laneSwing 2, laneFrequency 2.2, cornerAngle 0.5, cornerSpeed 18, straightSpeed 30, steerGain 1.65, brake 0.25, and skill with easy 0.65, normal 0.84, hard 1.

The three items are boost, shield (absorbs one pulse, not a crash) and pulse (a short-range flash that slows nearby karts). Every setting is moddable, inside the ranges of the schema.

Services, events, variables #

Services race.laps, race.items and vehicle.kart_drive all reach the same race:

  • start(): restarts the countdown with the existing racers.
  • restart(): the race again from the grid (the Restart of the pause screen); answers true.
  • playerVehicle(): the entity id of the player's kart.
  • standings(): the table of the racers.
  • resetToTrack(): the player's recover, with its penalty.
  • useItem(): uses the player's item.

Events: race.started; race.lap (entity, lap, player); race.pickup (entity, item, player); race.item (entity, item, player); race.boost (entity, source drift or pad, player); race.respawn (penalty, the player's kart); race.finished (seconds, position, the player); race.refused (decision, entity, player, reason), emitted when a hook cancelled a decision and never without one.

Variables: race.standings, race.position, race.lap, race.laps, race.seconds, race.countdown, race.item, race.shield, race.drift, race.boost, race.boosting, race.name, race.result.

Asset slots: race_driver binds the first pilot, race_driver_2 to race_driver_6 the other racers (a missing one uses the first); audio slots race_engine_audio, race_skid_audio, race_pickup_audio, race_boost_audio, race_finish_audio.

Hooks and modding #

Each decision is asked once, when the state changes, for the bots and the player alike; entity is the kart and player says whether it is the player's.

HookPayloadA tap mayCancelled
race.startentity, racers, lapscancelthe start is held (karts on the grid, clock stopped) until start()
race.pickupentity, player, crate, itemchange item, cancelan empty box: the kart gets nothing
race.useentity, player, item, durationchange duration, cancelthe item is kept
race.hitentity, player, by, item, shielded, durationchange duration, cancelimmunity: not slowed, shield kept
race.boostentity, player, source, durationchange duration, cancelno boost
race.recoverentity, player, reason, checkpoint, penaltychange penaltynot cancellable
race.finishentity, player, laps, penalty, position, secondschange secondsnot cancellable

reason of race.recover is reset, off_track or stuck. A crate's item is drawn before race.pickup is asked, so the following crates give the same items with or without a tap. A pulse on a shielded kart only removes the shield. Data taps of the project or of a mod need no code:

{ "id": "slow_rivals", "hook": "race.hit", "match": { "player": false }, "mul": { "duration": 2 } }
{ "id": "wait_for_intro", "hook": "race.start", "if": [{ "var": "intro.done", "op": "!=", "value": true }], "cancel": true, "reason": "intro" }

On game.engine the race belongs to the scene: its track is the scene's world, a scene may override countdown and difficulty, leaving a scene holds the karts and entering the next one puts them on the grid and starts a new race.

Engines #

The race rules are the same Rust module on the web and the native player. The Godot, Unity and Unreal deliveries race the same way (laps, standings, items, drift boosts, rivals, return to track) but do not run the hooks yet.

When it does not do what you expect #

  • The race never starts: a race.start tap cancelled it (see race.refused); call start() once it is allowed.
  • A kart gets no lap: it left the road width plus lateralSlack, or moved faster than the accepted travel per tick; raise travelSlack for very fast karts.
  • No item from a crate: items is false, the kart already holds one, or a race.pickup tap cancelled.
  • A bot sits still: it recovers after stuckSeconds below stuckSpeed.
  • The result is missing: race.result is written when the first racer has finished.

Limits #

  • Three items only, and the circuits belong to world.racetrack, not to this kit.
  • Up to 8 racers; the player is always the first.
  • The best time is kept per project and circuit in the browser only.

Versions #

Kit version 1.9.0 (services at 1.0.0). 1.7.0 added the hooks and the moddable settings; 1.9.0 added restart().