Animal behavior

Usage guide of animal.behavior: one named instance per animal that decides needs, fleeing, defense, hunting, herding and wandering, with confirmed effects, settings, commands, events, hooks and presets.

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

Also read offline — CLI: grip-forge docs animal-behaviorMCP tool: gripforge_docs { "topic": "animal-behavior" }

Animal behavior (animal.behavior) #

What it is for #

Individual animal decisions for a game: each animal is a named instance that keeps bounded needs (hunger, thirst, fatigue) and fear, and answers each step with a mode and, when it needs something from the world, an action to confirm. The engine keeps physics, navigation and every real effect. It does not move anything itself and invents no world effect: food, water, damage and paths are supplied by the game, and a bite or a sip counts only when the game confirms it.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "animal.behavior" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "animal.behavior", config: { "diet": "carnivore", "temperament": "defensive", "seed": 7 } }

Only the keys that differ from the defaults need to be written. Each animal is one named instance, created by the game; a fresh game already has one instance called default.

First example #

<!-- test: kits/game_engine/host/tests/animal_behavior.rs::feeding_is_confirmed_by_game_owned_resources_not_the_behavior_kit --> A hungry herbivore finds food: the kit asks to eat, the game consumes the food, then confirms with the token and the amount really eaten (hunger drops from 0.8 to 0.7).

create  ["deer", { "animalId": "e1", "hungerRate": 0 }]
request ["deer", { "op": "setNeeds", "hunger": 0.8, "thirst": 0, "fatigue": 0 }]
request ["deer", { "op": "step", "dt": 0.1, "position": [0,0,0], "velocity": [0,0,0], "alive": true,
                   "resources": [{ "id": "e2", "kind": "plant", "position": [0,0,0], "accessible": true }] }]
   -> { "mode": "eat", "action": { "kind": "eat", "token": 1, ... }, "needs": { "hunger": 0.8, ... } }
request ["deer", { "op": "resolve", "token": 1, "success": true, "amount": 0.1 }]
   -> hunger 0.7

Settings and defaults #

SettingDefaultMeaning
animalId"animal"Stable identity, excluded from its own perceptions
species"generic"Game-defined label; behavior comes from the other settings
diet"herbivore"herbivore, carnivore or omnivore: which food it seeks and whether it hunts prey
temperament"timid"timid flees; defensive defends when close or cornered; aggressive approaches and defends
space"ground"ground keeps the up-axis velocity; free steers in three dimensions (the engine owns gravity and collisions)
walkSpeed2Top speed for ordinary movement
runSpeed6Top speed when fleeing or pursuing (at least walkSpeed)
acceleration8Maximum steering acceleration on a valid path
senseRadius25Distance within which supplied observations count
dangerRadius12Distance at which a visible threat starts danger behavior
safeRadius20Fleeing keeps reacting out to this distance
defendDistance2Defensive animals defend inside this distance, or when unable to flee
attackReach1.5Maximum attack distance
hungerRate0.005Hunger gained per living simulation second
thirstRate0.008Thirst gained per second; 0 disables natural thirst
fatigueRate0.003Fatigue gained at runSpeed, scaled by observed speed
needThreshold0.6Need value (0 to 1) that starts seeking resources or resting
satisfiedThreshold0.2An ongoing need behavior continues until this value (below needThreshold)
restRecovery0.08Fatigue recovered per second while resting in a safe place the engine approves
fearDecay0.3Fear lost per second without refreshed danger
threatMemory3Seconds a vanished threat position is remembered
herdRadius12Range for supplied compatible herd members (≤ senseRadius)
separationDistance1Minimum desired spacing from herd members
followDistance3Desired distance from the herd centroid
wanderRadius8Radius of wander goals around home; 0 disables wandering
wanderInterval5Seconds before a new wander goal is chosen
arrivalRadius0.4Arrival radius at a resource, and tolerance for matching a navigation request
actionInterval1Minimum seconds between new food, water or attack requests
attackDamage10Maximum damage requested per attack (the combat system confirms the real effect)
biteAmount0.2Maximum hunger relief requested per confirmed bite
sipAmount0.3Maximum thirst relief requested per confirmed sip
seed1Nonzero deterministic seed; give each animal its own

Constraints are checked at creation: dangerRadius ≤ safeRadius ≤ senseRadius, walkSpeed ≤ runSpeed, attackReach ≤ defendDistance ≤ dangerRadius, separationDistance ≤ followDistance ≤ herdRadius ≤ senseRadius, satisfiedThreshold < needThreshold.

Commands #

step carries the observation: dt (at most a few tenths of a second), position, velocity, alive, and the lists the game can see: resources (food and water, each with id, kind, position, accessible), prey (with lineClear), threats, herd and navigation. The answer holds the mode (idle, wander, search_food, search_water, rest, flee, defend or hunt), the needs, and an action (eat, drink or attack) with a token when the world must be touched. resolve { token, success, amount } confirms or fails it; a stale token is refused. setNeeds { hunger, thirst, fatigue } sets the needs, preview { command } runs a command on a copy, and status, config, save and load read and restore.

Services #

The kit is a driver service: it decides only when the game calls it, never on its own tick.

  • create(id, config): creates a named instance (config is checked; at most 128 instances; an existing id is refused); returns the id.
  • request(id, command): sends one command object to an instance and returns its answer (unknown instance or invalid command: an error).
  • remove(id): removes an instance; returns whether it existed.
  • ids(): lists the instance ids.

status, config, save, preview and load are reads and state operations; step is the fixed-step command the game sends every tick. Every other command is a decision and goes through the request hook below.

What it announces #

NameDetail
animal.behavior.createdAn instance was created; payload { instance, preset }.
animal.behavior.removedAn instance was removed; payload { instance }.
animal.behavior.changedA decision command was applied; payload { instance, op, result }.
animal.behavior.refusedA tap of the request hook cancelled a decision; payload { instance, op, by, reason }.

Hooks and modding #

A game or a mod taps a hook with a document of its hooks list, without touching the kit:

  • animal.behavior.create: before an instance is created; payload { instance, preset, config }; a tap may replace config, or cancel (creation then fails with creation refused).
  • animal.behavior.request: before a decision command is applied; payload { instance, op, command }; a tap may replace command, or cancel: the call then answers { ok: false, cancelled: true, by, reason } and the refused event is emitted.
{ "id": "no_attacks", "hook": "animal.behavior.request", "match": { "op": "resolve" }, "cancel": true, "reason": "peaceful" }

Presets and scripts #

Presets. A document { "id": "<name>", "config": { … } } in the project data collection animal_behavior_presets names a ready-made tuning. create(id, { "preset": "<name>", … }) starts from it; the keys given next to preset win (shallow merge). An unknown preset is an error; the created event carries the preset name.

Scripts and rules can drive an instance with the action animal_behavior_request { instance?, command } (instance defaults to default) and test it with the condition animal_behavior_exists { instance? }.

When it does not do what you expect #

  • A command is refused with stale action token: the token is not the one of the pending action (or the action already ended); use the token of the last step answer.
  • setNeeds or save fails while an action is pending: confirm it with resolve first (a failed confirmation also ends it).

Limits #

  • No movement, pathfinding, gravity or collision: the game supplies valid navigation paths and applies the confirmed effects.
  • No hidden tick: nothing happens between two step commands, and time passes only by the dt the game sends.
  • Instances are saved and restored with the game (including the random generator, so a reload replays the same choices); a pending action must be resolved first.
  • Targets: the native kit host and the web player, from the same Rust core. The kit has no display module.

Versions #

1.1.0 (2026-10-19): game.engine hooks, presets, outcome events and script verbs; 1.0.0 (2026-10-16): first release. Requires no other kit.