NPCs
Usage guide of npc.core and npc.pedestrian: the NPC document, behaviours, perception, navigation, the pedestrian crowd, settings and defaults, events, hooks (npc.spawn, npc.switch, npc.respawn, pedestrian.spawn, pedestrian.hit), engines.
Non-player characters (npc.* kits) #
People that walk, see, hear and react, as data: the base kit, the ambient crowd of a city, and the conversations. Readable offline: gripforge docs npcs, or the MCP tool gripforge_docs (topic npcs).
What it is for #
| Kit | What it adds |
|---|---|
npc.core | the npcs collection: spawning in zones, locomotion on the ground or in the air, a sight cone and hearing, memory of the last known player position, a behaviour state machine (idle, wander, patrol, flee, investigate) other kits extend |
npc.pedestrian | a crowd wandering the sidewalks of a road network, fleeing fast vehicles, knocked down when hit |
npc.dialogue | typed lines and choices when the player talks to an NPC (described in the Quests and dialogue guide) |
Enemies are NPCs with health and attacks: see the Enemies guide.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "npc.core" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "npc.core", config: { "maxNpcs": 48 } }
gripforge_gamekit_install { project_id: "gkp_…", id: "npc.pedestrian" }
npc.core requires world.ground, spawn.entities, physics.port and game.engine; npc.pedestrian requires npc.core and a road network (world.roads, from the district kit). When the game has ai.navigation, NPCs follow collision-derived routes (closed or moving colliders invalidate them; an unreachable goal stops the NPC instead of cutting straight through walls).
The NPC document #
{ "schema": "gripforge.npc/1", "id": "guard", "faction": "town",
"locomotion": { "type": "walk", "speed": 1.6, "runSpeed": 4 },
"perception": { "sight": { "range": 18, "fov": 110 }, "hearing": 4, "memory": 8 },
"behavior": { "initial": "patrol", "behaviors": ["patrol", "idle", "investigate", "flee"],
"params": { "patrol": { "route": [[0,0,0],[10,0,0]], "wait": 2, "loop": true } } },
"assets": { "model": "guard" },
"spawn": { "zones": ["gate"], "count": 2 } }
assets.model names a model slot of the project; spawn.zones name zones of world.zones. locomotion.type is walk, static (it does not move) or fly; fly makes an NPC move freely in the air (it keeps the altitude it is sent to and never goes below the ground). A behaviour is registered by name: another kit adds its own (chase, hunt, ship_attack...), and the document lists which ones the NPC may use and which one it starts in. Placing: an archetype of kind npc with the component npc { doc }, or a spawn block in the documents of a scene (spawned on entering the scene, removed on leaving).
Settings and defaults #
| Kit | Key | Default | Meaning |
|---|---|---|---|
npc.core | tickHz | 10 | brain update rate (1 to 30); locomotion runs every tick |
npc.core | maxNpcs | 64 | live NPC cap |
npc.core | debug | false | emit npc.state on every transition (always on in tests) |
npc.pedestrian | count | 12 | pedestrians on the sidewalks (0 to 64) |
npc.pedestrian | walkSpeed / fleeSpeed | 1.5 / 4 | m/s |
npc.pedestrian | fleeRadius | 8 | a vehicle closer than this and faster than 5 m/s makes them flee |
npc.pedestrian | vehicleImpacts | true | web: continuous car and pedestrian hit detection, knockdown, recovery |
npc.pedestrian | bloodEffects | false | web: stylized droplets and temporary stains on impacts |
npc.pedestrian | bodyLifetime | 8 | seconds a lethally hit pedestrian stays visible |
npc.pedestrian | localPopulation | false | web: keep the crowd around the controlled player or car in a large world (populationRadius 100, recycleRadius 180) |
Services, events, variables #
npc.locomotion:moveTo,stop, path following (a flying NPC keeps its altitude).npc.perception:canSee(entity, target),heard(entity),lastKnown(entity).npc.behavior: register a behaviour, spawn, switch.pedestrian.ai:pedestrians(),count(),setDensity(n).- Events:
npc.spawned,npc.state({ entity, npc, from, to, target }),npc.despawned(reasondespawn,diedorremoved), and from pedestriansnpc.hit({ npc, entity, by, speed, direction, lethal, blood }), which a wanted-level kit counts as heat. - Condition
npc_state { npc, state }, verbnpc_state. - Slot
pedestrian(a rigged character, several allowed); a capsule is drawn until a model is bound.
Hooks and modding #
| Hook | Payload | What a tap may do |
|---|---|---|
npc.spawn | { npcId, faction, behavior } | cancel one NPC (the others still spawn) |
npc.switch | { entity, npcId, faction, from, to } | change to, cancel (the NPC stays in from) |
npc.respawn | { entity, npcId, faction, reason, delay } | change delay, cancel (it does not come back) |
pedestrian.spawn | { reason, x, y, z } | cancel (reason crowd, replace or recycle) |
pedestrian.hit | { npc, by, speed, damage } | change damage, cancel (no damage, no knockdown, no panic) |
{ "id": "brave_guards", "hook": "npc.switch", "match": { "faction": "town", "to": "flee" }, "set": { "to": "investigate" } }
Moddable: tickHz, maxNpcs, the pedestrian settings (bloodEffects aside), and the collection npcs (add, patch or remove documents).
Engines #
The brains, perception and the built-in behaviours are the same Rust logic on the web and in the native player, and are also delivered to Godot and Unity as files and to Unreal through the shared kit library. The local population of the pedestrians and the blood effects are web options; the native adapters keep the world-wide crowd. The hooks run on the web and in the Rust player.
When it does not do what you expect #
| Symptom | Cause and fix |
|---|---|
| An NPC never changes behaviour | the behaviour is not listed in its document's behavior.behaviors |
| No NPC appears | the spawn zone does not exist, maxNpcs is reached, or a tap cancelled npc.spawn |
| An NPC walks through walls | the game has no ai.navigation: add it for routes that follow the collisions |
| No pedestrians | the world has no road network, or the pedestrian slot is unbound (a capsule is drawn but the project is not reported playable) |
| A pedestrian is never hit | vehicleImpacts is off, or a pedestrian.hit tap cancels it |