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