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; } } }