Agents¶
An agent is a scene object that walks the navigation mesh by itself. Add a
PSXAgent component and the engine handles pathfinding, movement, vision, hearing
and a small state machine natively. An NPC that patrols a route and reacts to the
player needs no per-frame Lua at all.
Agents are built on navigation regions, so a scene needs a baked
nav mesh before they can move. That comes from a PSXPlayer, or - in a scene with
no player at all - from a
PSXNavigationSettings component. The agent
inspector tells you which one it found, and errors if there is neither.
Adding an agent¶
Add PSX Splash > PSX Agent to a GameObject that already has a
PSXObjectExporter. The component requires one and will add it for you.
Give the GameObject a name you can look up from Lua:
Settings¶
Movement¶
| Field | Default | Description |
|---|---|---|
| Start Enabled | on | Whether the agent ticks from scene load. Off means it stands still until Agent.SetEnabled. |
| Move Speed | 3.0 | World units per second, the same scale as the player's Move Speed |
| Stop Distance | 0.2 | How close counts as arrived. Reaching it fires onTargetReached. |
Vision¶
| Field | Default | Description |
|---|---|---|
| Has Vision | off | Enables the vision sense |
| Vision Range | 8 | Maximum sight distance in world units. 0 disables vision whatever the checkbox says. |
| Vision Fov Degrees | 90 | The full cone. 360 is omnidirectional inside the range sphere. |
| Vision Region Depth | 2 | How many nav-region portal hops line of sight may cross |
Vision Region Depth is the cost dial. 0 means the agent can only see inside
its own region, which is cheap and enough for a corridor. Each extra hop lets sight
pass through one more doorway and costs more CPU per check. 2 to 3 covers most
interiors.
Hearing¶
| Field | Default | Description |
|---|---|---|
| Has Hearing | off | Enables the hearing sense |
| Hearing Range | 6 | Radius in world units |
Hearing is range only. No geometry is consulted, so a target behind a wall is still heard. That is deliberate: it is what makes sound useful as the sense that gets around cover.
Alert¶
| Field | Default | Description |
|---|---|---|
| Alert Timeout Frames | 60 | Frames at 30fps the agent stays alert after losing the target |
The timeout is what stops an agent flickering between alerted and calm as the
target steps in and out of a doorway. onTargetLost fires when it expires, not
when sensing stops.
Patrol Waypoints¶
A world-space list, visited in order and looped. Maximum 8; the inspector
truncates anything longer. Reaching one fires onPatrolPoint(self, index) with a
0-based index.
An agent in the Idle state with waypoints moves to Patrol on its own.
State Animations¶
One animation clip per state. Entering a state plays its clip automatically; leave a slot empty to keep the previous animation running.
The state machine¶
| Value | State | What the engine does |
|---|---|---|
| 0 | Idle | nothing, but moves to Patrol if waypoints exist |
| 1 | Patrol | walks the waypoint list, looping |
| 2 | Seek | paths toward the current target actor |
| 3 | Flee | moves away from the current target actor |
| 4 | Attack | nothing - yours to drive |
| 5 | Wander | picks a random point near its nav region every ~60 frames |
| 6 | Investigate | walks to the last known target position |
| 7 | Custom | nothing, and never entered on its own |
Idle, Patrol, Seek, Flee, Wander and Investigate are driven natively. Attack and Custom exist so your Lua has somewhere to put behaviour the engine should stay out of.
Transitions between them are yours: sensing raises onTargetSeen, and it is your
script that decides whether that means Seek, Flee or Attack.
function onTargetSeen(self)
local me = Actor.Find(...)
Agent.SetState(me, 2) -- Seek
end
function onTargetLost(self)
local me = Actor.Find(...)
Agent.SetState(me, 6) -- Investigate the last known position
end
Editor gizmos¶
Selecting an agent draws its vision cone in yellow, its hearing radius in cyan, and its patrol route in green. Agents with any of the three configured draw a dimmer version even when not selected, so you can see a level's coverage at a glance.
Costs¶
- Vision and hearing are evaluated once per three frames, so an agent notices something up to 100ms late. The alert countdown ticks every frame regardless.
- Paths are recomputed every 10 frames while moving, not every frame.
- Each agent exports as a 28-byte record, so the memory cost is in the navigation mesh rather than in the agents themselves.
Vision Region Depth is the first thing to turn down
Line-of-sight across the portal graph is the expensive part of an agent. If a scene with several agents is dropping frames, drop the depth to 1 before changing anything else.
Pitfalls¶
Agent functions take actor handles, callbacks give entity handles
Agent.* and Actor.* take a handle from Actor.Find. The target argument
of onTargetSeen is an entity handle, and there is no conversion back.
See Event Callbacks for the lookup pattern.
Agent.SetVisionAngle takes the half angle
The inspector's Vision Fov Degrees is the full cone; the Lua setter takes
half of it. The 90 degree cone you authored is Agent.SetVisionAngle(a, 45).
An unreachable destination is silent
onPathBlocked exists but the engine never fires it. An agent that cannot
complete a route simply stops. Poll Agent.IsMoving against a timeout if that
would break your game.
See also¶
- Navigation & Collision - agents need a baked nav mesh
- Animations - the clips bound to each state
AgentAPI reference- Agent callbacks