Skip to content

Navigation and AI

SgNavMesh objects represent walkable surfaces for pathfinding. The nav mesh is built from scene geometry; scripts query paths and nearest points through the SgNavMesh API.

Placeable SgObstacle nodes punch dynamic holes (Tile cache only). SgAgent nodes register with the Crowd for locomotion and simple goals (GoTo, Patrol, Wander, Follow).

Setup

  1. Place walkable geometry in the scene (floors, terrain).
  2. Add an SgNavMesh object and bake/configure it in the editor. Enable Crowd if you will use SgAgent. Use Tile cache if you will use SgObstacle.
  3. Add SgAgent / SgObstacle nodes and link them to the nav mesh, or query paths from a behaviour script.

See SgNavMesh for field reference and the engine-api block generated from Lua comments.

SgAgent (Crowd)

Patrol waypoints are usually authored in the Inspector on the SgAgent: set Active goal to Patrol, then add ordered entries under Patrol waypoints. Each waypoint is either a world Point or a scene Node (empty marker groups work well). Enable Patrol loop to restart after the last point.

From a script you then start (or change) the goal — the agent walks the list already on the node:

local SgAgent = require 'engine/sceneobjects/sgagent'
local Vector3 = require 'engine/math/vector3'

-- On a Behaviour attached to an SgAgent that already has Patrol waypoints
-- (and a Nav mesh) set in the Inspector:
function Guard:init()
    self.node:setGoal(SgAgent.GoalType.Patrol, {
        loop = true,  -- optional; mirrors the Patrol loop field
    })
    self.node:on("waypointReached", function(ev)
        print("waypoint", ev.data.index)
    end)
    self.node:on("goalReached", function(ev)
        -- Fires when Patrol finishes without loop
        print("goal done", ev.data.goalType)
    end)
end

function Guard:onInteract()
    -- Temporary detour; return to patrol afterward if you call setGoal(Patrol) again
    self.node:setGoal(SgAgent.GoalType.GoTo, {
        point = Vector3.new(0, 0, 10),
        urgency = SgAgent.Urgency.Run,
    })
end

setGoal(Patrol, …) does not take a waypoint list — only options such as loop. Without at least one Patrol waypoints entry the agent has nowhere to go and stays put.

Event details: Node Game Events.

Typical low-level path loop

local SgNavMesh = require 'engine/sceneobjects/sgnavmesh'
local Vector3 = require 'engine/math/vector3'

-- navMesh reference via Property.Node or findByName
Agent:addProperty("navMesh", Property.Node)

function Agent:update(deltaTimeMs)
    if not self.path or #self.path == 0 then return end

    local target = self.path[self.pathIndex]
    local pos = self.node.transform.position
    local dir = target:sub(pos):normalized()
    local dt = deltaTimeMs / 1000

    self.node:translate(dir.x * self.speed * dt, 0, dir.z * self.speed * dt)

    if Vector3.distance(pos, target) < 0.5 then
        self.pathIndex = self.pathIndex + 1
    end
end

function Agent:moveTo(destination)
    -- Request path from nav mesh API (see SgNavMesh reference)
    -- self.path = ...
    -- self.pathIndex = 1
end

Use Physics Scripting raycasts for line-of-sight checks alongside nav paths.

Vehicles

Wheeled vehicles use SgVehicle instead of navmesh steering. See SgVehicle.

Further reading