Skip to main content

Fundamentals

Core Concepts

All sensors share some concepts in common:

  • A Sensor is a Component that has a list of Signals.
  • Each Signal stores one detected GameObject and some data about the objects shape and visibility.
  • A Sensor can Pulse, causing it to run its sensing routine and update its list of Signals.
  • Some sensors are Compound, they read the Signals from another sensor and run additional detection logic.

There are edge cases, but this is a good framework for understanding the kit. If a sensor deviates then it will be explained on its manual page.

Sensor

Almost all of the sensors derive from a common base class Sensor. It provides a standard interface for querying what a Sensor can detect and hooking into its events. You can read its API page here. Only the NavMeshSensor and SteeringSensor do not derive from Sensor.

Signal

A Signal is a small data structure that references a detected GameObject and holds a bit of information about the detection. The data it holds is as follows:

  • Object - The GameObject that is detected.
  • Strength - A value representing how visible the signal is.
  • Shape - A bounding box approximating the shape that the object appears to be.

A sensor will have at most one Signal for any GameObject.

Pulse

Most sensors have a Pulse action that runs its detection routines. A list of signals is generated and compared to the previous list. Events are fired for new detections and for lost detections. You can configure when a sensor will pulse by setting its PulseMode. The modes available are:

  • Each Frame - The sensor will pulse each frame in the Update stage.
  • Fixed Interval - The sensor pulses at a regular time interval in seconds. This is recommended where possible for optimising performance. The intervals are staggered with a random offset so sensors with equal intervals are spread across frames.
  • Manual - The sensor will only pulse if you invoke its Pulse() method via script or PlayMaker.

Scripting API

All classes are in the Micosmo.SensorToolkit namespace. A simple script that reads a sensor might look like this:

using UnityEngine;
using Micosmo.SensorToolkit;

public class AIBehaviour : MonoBehaviour {
public Sensor sensor;

void Update() {
var pickup = sensor.GetNearestDetection("pickup");
if (pickup != null) {
// Collect it...
}
}
}

Of course it's also possible to subscribe to the OnDetected and OnLostDetection events instead so it's not necessary to check the sensor each frame.

Garbage Collector Optimisation

Special care was taken to design SensorToolkit so that it never allocates GC. If you call a function that returns a List I will have implemented it so the same List instance is returned each time. The goal being that it's super-convenient to return a list of detections and iterate over them.

List<Signal> enemies = sensor.GetSignals("enemy");  // Get all signals with tag "enemy"
List<Signal> friends = sensor.GetSignals("friend"); // ⚠️ 'enemies' will be overwritten
enemies == friends; // True
List<Signal> items = sensor.GetSignalsByDistance("item"); // ⚠️ different methods will also overwrite the List
enemies == items; // True

List<Signal> coverLocations = coverSensor.GetSignalsByDistance(); // ✔️ no issue here. Each sensor allocates its own reusable list.

To fix this you can write:

// An optional last parameter let's you provide your own instance of List
List<Signal> enemies = sensor.GetSignals("enemy", new List<Signal>());
List<Signal> friends = sensor.GetSignals("friend", new List<Signal>());
enemies == friends; // False