74 lines
2.7 KiB
C#
74 lines
2.7 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Unity Layer for the light objects
|
|
/// </summary>
|
|
/// This is used to improve performance
|
|
[Tooltip("Unity Layer for the light objects")]
|
|
public LayerMask senseLayer;
|
|
|
|
/// <summary>
|
|
/// Output value of the sensor
|
|
/// </summary>
|
|
[Tooltip("Output value of the sensor")]
|
|
public float output => _output; //{ get; protected set; }
|
|
public float _output;
|
|
|
|
protected Vehicle vehicle;
|
|
protected ClusterPrefab brain;
|
|
public Neuron sensoryNeuron;
|
|
|
|
protected virtual void Awake() {
|
|
if (vehicle == null)
|
|
vehicle = GetComponentInParent<Vehicle>();
|
|
if (vehicle != null)
|
|
brain = vehicle.brain;
|
|
if (brain != null)
|
|
sensoryNeuron = brain.GetNucleus(this.name) as Neuron;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
} |