using System.Collections; using UnityEngine; namespace NanoBrain.Braitenberg { using Unity; public class Sensor : MonoBehaviour { [Tooltip("Max distance sensor detects anything")] public float sensorRange = 10f; [Tooltip("Time between samples (s).")] 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 => _output; //{ get; protected set; } public float _output; protected Vehicle vehicle; protected Cluster brain; public Neuron sensoryNeuron; protected virtual void Awake() { if (vehicle == null) vehicle = GetComponentInParent(); if (vehicle != null) brain = vehicle.brain; if (brain != null) sensoryNeuron = brain.GetNeuron(this.name); } void OnEnable() => StartCoroutine(SampleRoutine()); void OnDisable() => StopAllCoroutines(); IEnumerator SampleRoutine() { WaitForSeconds wait = new(sampleInterval); while (true) { _output = SampleSensor(); sensoryNeuron?.ProcessStimulus(Vector3.one * (_output+0.00001f)); yield return wait; } } protected virtual float SampleSensor() { // Cast a short set of rays in a cone and accumulate "brightness" from hits. int rays = 7; float halfAngle = 30f; float total = 0f; for (int i = 0; i < rays; i++) { float t = rays == 1 ? 0.5f : (float)i / (rays - 1); float angle = Mathf.Lerp(-halfAngle, halfAngle, t); Vector3 dir = Quaternion.AngleAxis(angle, this.transform.up) * this.transform.forward; Debug.DrawRay(this.transform.position, dir * sensorRange); if (Physics.Raycast(this.transform.position, dir, out RaycastHit hit, sensorRange, senseLayer)) { // Strength inversely proportional to distance, clamped to [0,1] float str = 1f - (hit.distance / sensorRange); // You can also sample material emission or color here if desired total += Mathf.Clamp01(str); } } return Mathf.Clamp01(total / rays); } } }