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
- Place walkable geometry in the scene (floors, terrain).
- 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.
- 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
- SgNavMesh
- SgAgent
- SgObstacle
- SgPlayer
- SgVehicle
- Scene Graph — moving agents, tags, layers
- Math and Transforms — positions and directions