Sensor Controller¶
The SensorController manages the lifecycle of all sensors attached to an agent. It polls each sensor at its configured interval and handles staggered timing to prevent CPU spikes.
How Sensors Work¶
Sensors are the primary data producers in the GOAP pipeline. They read world state (vision cones, proximity checks, waypoints, sound) and write results to the blackboard.
- Each sensor is a ScriptableObject (
GoapSensorSO) defined on the Brain. - The
SensorControllerpolls each sensor at itsUpdateInterval(default 0.5s). - First-tick timing is staggered using a deterministic offset based on the agent's InstanceID, preventing all agents from polling on the same frame.
- Sensor outputs are mapped to blackboard keys via the Brain's Key Manifest.
Warning
Sensors do not fire every frame. Any blackboard key written by a sensor may be up to one full interval old when read. Design all code that reads sensor-driven keys to tolerate stale data.
Output Declaration¶
Every sensor declares what it outputs using GetOutputs():
public override SensorOutputConfig[] GetOutputs() => new[]
{
new SensorOutputConfig("TargetPosition", GoapKeyType.Vector3),
new SensorOutputConfig("Found", GoapKeyType.Boolean),
};
Each output is a named slot with a data type. The GOAP Hub maps these output slots to concrete blackboard keys in the Key Manifest.
GoapKeyType¶
| Type | C# Type |
|---|---|
Boolean |
bool |
Float |
float |
Vector3 |
Vector3 |
Integer |
int |
Object |
GameObject |
String |
string |
Write Helpers¶
Sensors use typed write helpers that automatically handle temporal key routing:
// Simple writes (non-temporal)
WriteBool(settings, blackboard, "Found", true);
WriteFloat(settings, blackboard, "Distance", 12.5f);
WriteInt(settings, blackboard, "Count", 3);
WriteGameObject(settings, blackboard, "Target", targetGO);
// Vector3 write WITHOUT entity tracking
WriteVector3(settings, blackboard, "Position", pos);
// Vector3 write WITH entity tracking (for temporal/recollection keys)
WriteVector3(settings, blackboard, "Position", pos, targetGameObject);
Temporal Key Routing¶
The write helpers automatically check if a key is managed by the RecollectionSystem:
- If the key is temporal, the helper calls
ReportStimulus()instead of writing directly. - If the key is not temporal, the helper writes directly to the blackboard.
Tip
Always use WriteVector3 with the target parameter when writing position data for entities that should be tracked in memory. This enables confidence decay and multi-entity tracking.
Built-In Sensors¶
The framework ships with four sensors. Create them via Create > RGS > GOAP > Sensors > {name}.
Optical Sensor¶
Vision cone with line-of-sight raycast.
| Output | Type | Description |
|---|---|---|
| Position | Vector3 | Target's world position |
| Found | Bool | Whether a valid target is within the vision cone |
| HasDirectSight | Bool | Whether a clear line of sight exists (raycast check) |
Configurable: field of view angle, range, target layers, target tags, occlusion layers.
Auditory Sensor¶
Reads noise events from NoiseEmitter components.
| Output | Type | Description |
|---|---|---|
| SoundPosition | Vector3 | Position of the detected noise |
Pairs with the NoiseEmitter component on sound-producing GameObjects.
Sphere Sensor¶
Proximity detection using Physics.OverlapSphere.
| Output | Type | Description |
|---|---|---|
| TargetPosition | Vector3 | Nearest valid target's position |
| TargetObject | Object | Reference to the nearest valid target |
| FoundTarget | Bool | Whether any valid target was detected |
Configurable: radius, target layers, target tags.
Waypoint Sensor¶
Reads the current waypoint from WayPointManager.
| Output | Type | Description |
|---|---|---|
| WaypointPosition | Vector3 | World position of the current waypoint |
| IsAtWaypoint | Bool | Whether the agent is within arrival distance |
Pairs with the WayPointManager component for patrol routes.
NoiseEmitter¶
Attach NoiseEmitter to GameObjects that produce sound. The AuditorySensorSO reads emitted noise events.
public class NoiseEmitter : MonoBehaviour
{
public void EmitNoise(NoiseType type);
public void EmitNoise(NoiseType type, float radius);
}
SensorUtils¶
Utility class for target validation:
public static class SensorUtils
{
// Validates a detected GameObject against layer mask and tag filters
public static bool IsValidTarget(GameObject obj, LayerMask mask, string[] tags);
}
Sensor Timing Details¶
| Setting | Default | Description | Notes |
|---|---|---|---|
UpdateInterval |
0.5s | How often the sensor fires | Range: 0.1–2.0s. Lower = more responsive, higher CPU. See Performance Tuning. |
| Stagger offset | Automatic | First tick offset based on agent InstanceID | Distributes sensor polls evenly across frames to prevent CPU spikes. |
The staggering ensures that if you have 100 agents, their sensor polls are distributed evenly across the 0.5-second window rather than all firing on the same frame.
Tip
Tune intervals per-sensor based on importance. Vision sensors that drive state transitions may need 0.2s, while waypoint sensors can safely use 1.0s.
See Also
- Blackboard — Regular Keys vs Temporal Keys — How sensor writes route to regular vs temporal keys
- GOAPAgent — The component that owns the SensorController
- Performance Tuning — Tuning sensor intervals for large agent counts
- Glossary — Quick definitions for Sensor, Temporal Key, and related terms
What's Next¶
- Custom Sensors — Build your own sensor from scratch with a complete template.
- Blackboard — Understand the key-value store that sensors write to.
- Action Strategies — How strategies read sensor data from the blackboard.