A sensor performs checks for a transition within a scenario sequence. When the check suceeds for all its sensors (resulting in a logical AND), the transition can be fired, except in the case of decision trees where the transition fires whether the sensors return true or false.
A transition can hold multiple sensors. When the scenario engine updates a transition, it will check its sensors in the order they appear. If a sensor returns false, the following sensors on the transition won't be evaluated. When the check step of the transition is finished (i.e. all sensors returned true or one sensor returned false), the scenario engine will call PostCheck() on all the sensors of the transition, whether they where previously evaluated or not.
AInUnityStepSensor can be used for sensors that need to be checked in Unity's execution steps (FixedUpdate, Update, LateUpdate, ...). These sensors will also trigger a scenario update as soon as they are validated, resulting in a more reactive scenario.
AUnitySensor can be used for sensors that only need to be checked when the scenario updates. Usually the scenario is updated at a fixed delta time (as set in the XareusManager component for example).
ASensor is the base class of all sensors and is usually used for sensors that do not involve Unity3D code at all.
How to create a sensor for Unity?
To create a custom Unity sensor, create a new C# script within the project. For convenience, the script name should end up with Sensor
and should be located within a Sensors
folder.
A Unity sensor must inherit from AUnitySensor or, in most cases, from AInUnityStepSensor. They help build a sensor that will execute code within the Unity thread. A sensor that does not require any code to run within a Unity thread can directly inherit from the parent abstract class ASensor.
A sensor can contain fields and properties that can be tagged using a Configuration Parameter attribute.
At runtime, after the sensor is constructed, the value of the fields and properties with the Configuration Parameter attribute will be filled (this happens before @Xareus.Scenarios.Sensor.Reset or SafeReset() is called) and updated if necessary (this happens before @Xareus.Scenarios.Sensor.SensorCheck or SafeSensorCheck() or UnityStepSensorCheck() is called)
You can use the Event Context Entry attribute to indicate strings that will be used as keys in the resulting EventContext (see below). These keys are used in the scenario editor to help the user know which values can be used when using the EventContext in other elements of the transition.
You need to call the base constructor when inheriting this class and implement the SafeReset() (optional) and UnityStepSensorCheck() (mandatory) methods.
- SafeReset() is responsible of the sensor initialization. It will be called in Unity's thread after the field and properties values are set and every time a sensor needs to be reset.
- UnityStepSensorCheck() is the actual sensor code that will be executed in Unity's thread and at each Unity's execution steps depending on the @Xareus.Scenarios.Unity.AInUnityStepSensor.ExecutionStep property value, whether the scenario is threaded or not.
A AInUnityStepSensor sensor automatically calls UnityStepSensorCheck(). While active, a sensor updates its parameters at every scenario update (in other words, while the UnityStepSensorCheck() method is called at each unity step, the parameters are not updated at each Unity execution step !).
UnityStepSensorCheck() will produce a ASensor.Result. It contains a Boolean Success and an EventContext.
Success indicates if the check was sucessful or not. EventContext contains a context produced by the sensor. This context should limit itself to the event handled by the transition.
More details regarding contexts
A sensor can manipulate other contexts: external context, scenario context, sequence context.
- The external context corresponds to the world context created in Unity.
- The scenario context is a set of data common to the whole scenario. It can be interpreted as global variables for the scenario.
- The sequence context (or token) is a set of data contained by the token moving through the transition holding this sensor. Think of it as a local variables
IContext is an interface. It defines the way a context works. Contexts should be manipulated as IContext.
The ASensor.Result that is manipulated by the sensors is meant to return a boolean indicating if the sensor was triggered and the data of type IContext about how the sensor was triggered, called the Event Context
.
When setting data in the Event Context
, you will most likely use key/value pairs. We recommend extracting the key string value into a static variable with the EventContextEntryAttribute attribute (see examples below). This will help the scenario editor show available EventContext paths to the user.
Examples
using Xareus.Scenarios.Context;
using Xareus.Scenarios.Utilities;
using Xareus.Scenarios.Unity;
[FunctionDescription("A Unity Sensor")]
public class ExampleSensor : AInUnityStepSensor
{
// A key that will be used in the EventContext
[EventContextEntry()]
public static readonly string KEY = "key";
// A configuration parameter for the sensor that will be displayed
// in the scenario inspector
[ConfigurationParameter("Parameter", Necessity.Required)]
protected string parameter;
// The event context that will be returned
private SimpleDictionary eventContext = new SimpleDictionary();
public ExampleSensor(Xareus.Scenarios.Event @event,
Dictionary<string, List<string>> nameValueListMap,
IContext externalContext,
IContext scenarioContext,
IContext sequenceContext)
: base(@event, nameValueListMap, externalContext, scenarioContext, sequenceContext)
{ }
public override void SafeReset()
{
//Initial operations and checks
}
public override Result UnityStepSensorCheck()
{
// Check performed each time the unity steps configured
// in the ExecutionStep property are performed
...
if (valid)
{
eventContext.Add(KEY, value);
}
return new Result(valid, eventContext);
}
}
Note
Several sensors are shipped with Xareus, some of them are open sourced so you can use them as an inspiration to create custom sensors.