Recipes
NPC and enemy navigation chase and patrol behavior
An entity should move itself toward a point or a target without a player driving it.
NavAgentComponent is the one navigation behavior; it steers through the existing mover over the recast navmesh (there is no navmesh-as-component and no second mover).engine v1.0.234since component-field-contract ecs.component-field-contract.v1, world.v1, script-semantic-patch-ops.v1Copy for LLM
Use this for
enemies that chase the player; NPCs that walk to a destination; patrol routes; agents steered across the world navmesh
Not for
player-controlled movement (see first-person-controls or third-person-and-platformer-movement); flying or scripted-path movers with no navmesh
Pairs with: Combat damage health and respawn scripting, Third-person follow camera and platformer jump movement, Spawn points checkpoints and respawn flow
The recipe
- Attach
NavAgentComponentwithproject_add_component(project.entity.component.set):{ "type":"NavAgentComponent", "enabled": true, "speed": 4, "arrivalRadius": 0.5, "destination": {"x":0,"y":0,"z":0} }.speedandarrivalRadiusare 0..1000. - To chase a specific entity, set
targetEntityKeyto that entity's project graph key; the agent follows it. To walk to a fixed point, setdestination. - Give the agent a body: a
RenderableComponentto be seen and aColliderComponentso it collides. Do not addCharacterMovementComponent; the nav system already owns the mover. - For decisions (acquire target, switch patrol point, give up), author a script with
addTickHandler{ "handlerKey":"onThink" }. Inside a GessaScript body usectx.world.find/ctx.world.queryto locate the player,ctx.navigation.isReachable/ctx.navigation.findPathto test the route, and patch theNavAgentComponentdestination/targetEntityKeywithctx.entity.patchComponent. - For a patrol, keep a small list of points in a script variable and advance to the next when the agent is within
arrivalRadius.
Pitfalls
NavAgentComponentneeds a walkable navmesh in the world; over empty space or off-mesh, the agent cannot path. Confirm the ground is navigable.targetEntityKeyis a project graph key (semanticproject_graph_key), not a raw UUID; use the entity's key.- Steering happens through the shared mover; do not stack a second movement component expecting additive motion.
- Path decisions belong in a throttled tick handler, not every frame of heavy work; keep per-tick queries bounded (SWE-agent ACI discipline: small, purposeful steps).
Verify
engine_get_component_schemaonNavAgentComponentfor the exact fields and bounds.simulation_run(qa.run.start) to prove the agent reaches its destination or closes on its target.qa_capture_renderer_viewportto see the agent move.