using System.Collections;
using UnityEngine;
namespace NanoBrain.Unity.Braitenberg {
///
/// A non-directional sensor
///
/// The sensor has a field of view, but the signal returned does not include a direction
[HelpURL("https://passer.life/documentation/nanobrain/Documentation/html/class_nano_brain_1_1_unity_1_1_braitenberg_1_1_sensor.html")]
public class Sensor : MonoBehaviour {
///
/// Maximum distance the sensor detects anything
///
[Tooltip("Max distance sensor detects anything")]
public float sensorRange = 10f;
///
/// Time between samples in seconds
///
[Tooltip("Time between samples (sec.)")]
public float sampleInterval = 0.1f;
///
/// Unity Layer for the light objects
///
/// This is used to improve performance
[Tooltip("Unity Layer for the light objects")]
public LayerMask senseLayer;
///
/// Output value of the sensor
///
[Tooltip("Output value of the sensor")]
public float output { get; protected set; }
///
/// The NanoBrain::Neuron which is stimulated by this sensor
///
public Neuron sensoryNeuron;
///
/// Unity calls Awake when loading an instance of a script component.
///
protected virtual void Awake() {
Vehicle vehicle = GetComponentInParent();
if (vehicle == null)
return;
Cluster brain = vehicle.brain;
if (brain == null)
return;
sensoryNeuron = brain.GetNeuron(this.name);
}
///
/// Called when a component of an active GameObject is first enabled.
///
void OnEnable() => StartCoroutine(SampleRoutine());
///
/// Called when a component itself is disabled or its parent GameObject is deactivated.
///
void OnDisable() => StopAllCoroutines();
///
/// The sensor samping routine.
///
/// IEnumerator such that it can run as a Unity Coroutine
/// The sample rate is defined by sampleInterval
/// This also stimulates the sensoryNeuron if is has been found.
private IEnumerator SampleRoutine() {
WaitForSeconds wait = new(sampleInterval);
while (true) {
output = SampleSensor();
sensoryNeuron?.ProcessStimulus(Vector3.one * (output + 0.00001f));
yield return wait;
}
}
///
/// Performs a sampling function to retrieve a new sensor output value
///
/// 0.0
/// This is a dummy implementation which always returns 0.0
/// because this component is an abstract sensor
protected virtual float SampleSensor() {
return 0.0f;
}
}
}