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.
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:
race.laps.playerVehicle()answers the entity of the player's kart;race.laps.standings()answers the table.resetToTrack()and the keyRreturn the kart to its last checkpoint (race.respawn, with a penalty).Euses the held item (race.item),Wand a steering axis drive, and the standings are read again until the finish (race.finished).
Settings and defaults #
| Setting | Type | Default | Meaning |
|---|---|---|---|
racers | integer (1..8) | 6 | number of karts; the first is the player |
countdown | number (0..5) | 3 | seconds before the start |
difficulty | easy, normal, hard | normal | bot target speed times bots.skill |
items | boolean | true | crates and items |
driverNames | list of strings | [] | names that replace the default ones (You, Nova, Mako, Pip, Tess, Sol, Ash, Rue) |
camera | distance, height | 8.5, 4 | chase camera, metres |
grid | start, spacing, lane, spawnStart, spawnSpacing | 5, 5, 2.1, 0.01, 0.008 | first row behind the line, row gap, column offset (m); first spawn in track fractions |
progress | see below | laps, recovery and road edge | |
drift | see below | drift charge and mini-turbo | |
boost | pad, padRadius, minTank | 1.4, 3, 30 | pad boost seconds, pad half-length (m), tank floor while boosting |
itemRules | see below | items and crates | |
bots | see below | bot driving |
progress:checkpoints16 per lap;recoverPenalty2 s;travelMin2,travelFactor3,travelSlack1 (accepted travel per tick, so teleports and infield cuts never award laps);lateralSlack2;edgeInset0.9 andedgeDamping0.94 (karts are held inside the road edge);offTrack15 andfallY-3 (beyond these a kart recovers);stuckSpeed1 andstuckSeconds4 (a stuck bot recovers).drift:minSlip0.18,minSpeed8,resetSpeed7,maxCharge2.4,tier10.65,tier21.6,boost11.15,boost22.1. Releasing with a charge of at leasttier1givesboost1seconds of boost; at leasttier2givesboost2.itemRules:boost2.5 andshield6 (seconds),pulseTime0.5,pulseRadius15,slowTime1.5,slowDamping2,slowThrottle0.1,crateRadius3,crateRespawn3,crateHeight0.9,crateLanes0.29,botUseEvery5.bots:lookahead8,lookaheadPerSpeed0.5,laneSwing2,laneFrequency2.2,cornerAngle0.5,cornerSpeed18,straightSpeed30,steerGain1.65,brake0.25, andskillwitheasy0.65,normal0.84,hard1.
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); answerstrue.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.
| Hook | Payload | A tap may | Cancelled |
|---|---|---|---|
race.start | entity, racers, laps | cancel | the start is held (karts on the grid, clock stopped) until start() |
race.pickup | entity, player, crate, item | change item, cancel | an empty box: the kart gets nothing |
race.use | entity, player, item, duration | change duration, cancel | the item is kept |
race.hit | entity, player, by, item, shielded, duration | change duration, cancel | immunity: not slowed, shield kept |
race.boost | entity, player, source, duration | change duration, cancel | no boost |
race.recover | entity, player, reason, checkpoint, penalty | change penalty | not cancellable |
race.finish | entity, player, laps, penalty, position, seconds | change seconds | not 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.starttap cancelled it (seerace.refused); callstart()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; raisetravelSlackfor very fast karts. - No item from a crate:
itemsisfalse, the kart already holds one, or arace.pickuptap cancelled. - A bot sits still: it recovers after
stuckSecondsbelowstuckSpeed. - The result is missing:
race.resultis 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().