# gander navigation and AI Navmeshes, paths, cover, and crowds of agents that walk them. Everything is `gander::` in Goose. Enemy brains stay your own code (a state machine with `enum` + `match`); the engine answers "how do I get there", "where can I hide" and moves bodies around walls and each other. ## Build a navmesh once ```goose var nav: gander::Nav; fn main() { // ... build the level (walls as MESH_CUBE boxes, models, terrain) nav = gander::nav(gander::NavSettings { radius: 0.4, height: 1.8 }); gander::nav_add_mesh(nav, gander::MESH_CUBE, floor_xf); for w in walls { gander::nav_add_mesh(nav, gander::MESH_CUBE, w); } gander::nav_add_model(nav, house, house_xf); // rest pose, skinned parts skipped gander::nav_add_terrain(nav, land, gander::v3(0.0, 0.0, 0.0), 150.0); // ground within 150 m gander::nav_link(nav, ledge_top, ledge_bottom, false); // a drop only walked down if !gander::nav_build(nav) { gander::fail("no walkable navmesh"); } } ``` Add every walkable and every blocking surface: floors, walls, stairs, props big enough to walk around. `NavSettings`: `radius` (how close to walls), `height` (headroom), `climb` (tallest step), `slope` (degrees), `cell` (voxel size: 0 = radius / 2, good indoors; 0.3 to 0.5 for large outdoor areas, it builds much faster), `tile` (meters per tile, 32). `nav_add_terrain` samples the ground every 4 cells (at least 1 m), too coarse for trenches and ditches a few metres wide: `nav_add_terrain_detail(nav, land, center, radius, step)` takes the step (0 = every height sample; keep the radius to where agents walk). One `Nav` per agent size: a soldier and a tank need two. The log prints tiles, polygons and build time; `nav_debug(nav, color)` draws the polygon edges. ## Paths and queries ```text nav_path(nav, a, b, out: float3[>..]&) -> bool corners of the shortest walk; false when no way (cut off: ends as near as it gets, still true) nav_closest(nav, p) -> float3 snap a point onto the mesh nav_on(nav, p) -> bool is p standing on it nav_raycast(nav, a, b) -> f32 1 = a straight walk gets there; less = a wall or drop first nav_random(nav, center, radius) -> float3 a reachable point (patrols, wandering, spawns) nav_cover(nav, near, radius, threat, out&) -> i32 spots beside walls that hide them from threat, nearest first nav_block(nav, center, size, yaw) -> i32 id closed doors, barricades, a burning car nav_unblock(nav, id) (the touched tiles rebuild over the next frames) ``` `nav_raycast` is line of sight on the floor plan: a cheap "can that guard see the player" before a real `raycast` against physics bodies. `nav_cover` uses the navmesh's walls (tall cover). ## Agents (crowds) The engine walks agents every frame with steering, avoidance and separation; your code decides where they go. ```goose let a = gander::agent_add(nav, spawn, 3.5); // speed m/s gander::agent_move(nav, a, gander::camera_pos()); // re-send when the target moves (a few times a second is plenty) let p = gander::agent_pos(nav, a); // draw the character here let v = gander::agent_vel(nav, a); // face it: yaw = atan2(-v.x, -v.z); pick walk / run by length(v) if gander::agent_arrived(nav, a, 1.0) { ... } // within 1 m of where it was sent ``` `agent_stop`, `agent_teleport`, `agent_speed` (sprint, limp), `agent_remove` (dead: then play a ragdoll from its last position). Up to 128 agents per `Nav`. Agents stand on the navmesh; for jumping or flying enemies, move them yourself and use `nav_path` for the route. ## Recipes **Patrol, chase, search.** State machine per enemy: `Patrol` sends the agent to `nav_random` points (or a list), `Chase` re-sends `agent_move` to the player every 0.25 s while `nav_raycast(nav, eye, player) == 1.0` or a physics `raycast` sees them, `Search` goes to the last seen point then patrols nearby. **Turn to face, then act.** A creature standing still that must face the player (to attack, to breathe fire) turns with its turn clips, not by a rate over its idle: when the angle to the target passes ~40 degrees, play turn_l / turn_r / turn_180 with `anim_root_turn` on and add `anim_root_yaw` to its yaw (the recipe "Turning in place with turn clips" in the API sheet's animation section); attack once it ends. Moving agents keep facing their velocity. **Take cover and shoot.** On first contact: `nav_cover(nav, my_pos, 12.0, player, spots)`, send the agent to `spots[0]`, and when it arrives alternate crouched (behind cover) and standing (fire) every couple of seconds. **Circle and take turns (melee).** Let only one or two enemies attack at once; send the rest to points on a ring around the player (`player + v3(cos(a), 0, sin(a)) * 4`, snapped with `nav_closest`), moving their angles a little each second. **Doors.** `nav_block` the doorway while it is shut and `nav_unblock` when it opens; agents re-route by themselves.