Gessa Docs
Recipes

Recipe

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

  1. Attach NavAgentComponent with project_add_component (project.entity.component.set): { "type":"NavAgentComponent", "enabled": true, "speed": 4, "arrivalRadius": 0.5, "destination": {"x":0,"y":0,"z":0} }. speed and arrivalRadius are 0..1000.
  2. To chase a specific entity, set targetEntityKey to that entity's project graph key; the agent follows it. To walk to a fixed point, set destination.
  3. Give the agent a body: a RenderableComponent to be seen and a ColliderComponent so it collides. Do not add CharacterMovementComponent; the nav system already owns the mover.
  4. For decisions (acquire target, switch patrol point, give up), author a script with addTickHandler { "handlerKey":"onThink" }. Inside a GessaScript body use ctx.world.find / ctx.world.query to locate the player, ctx.navigation.isReachable / ctx.navigation.findPath to test the route, and patch the NavAgentComponent destination/targetEntityKey with ctx.entity.patchComponent.
  5. 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

  • NavAgentComponent needs a walkable navmesh in the world; over empty space or off-mesh, the agent cannot path. Confirm the ground is navigable.
  • targetEntityKey is a project graph key (semantic project_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_schema on NavAgentComponent for 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_viewport to see the agent move.
Was this helpful?Report an issueContact support

On this page