using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; public class Receptor : IReceptor { private Cluster cluster; [SerializeField] protected string _name; public virtual string name { get => _name; set => _name = value; } public Receptor(Cluster cluster) { this.cluster = cluster; if (cluster != null) cluster.prefab.nuclei.Add(this); } public Receptor(Cluster cluster, INucleus nucleus) { this.cluster = cluster; if (cluster != null) cluster.prefab.nuclei.Add(this); this.AddReceiver(nucleus); } public static Receptor CreateReceptor(Cluster cluster, string nucleusName) { if (cluster == null) return null; Receptor receptor = new(cluster); foreach (INucleus nucleus in cluster.prefab.inputs) { if (nucleus != null && nucleus.name == nucleusName) { // Receptor receptor = new(cluster, nucleus); // return receptor; receptor.AddReceiver(nucleus); } } if (receptor._receivers.Count == 0) return null; else return receptor; } public virtual IReceptor CloneTo(Cluster parent) { Receptor clone = new(parent); foreach (INucleus receiver in this.receivers) { clone.AddReceiver(receiver); } return clone; } public virtual IReceptor Clone() { Receptor clone = new(this.cluster); foreach (INucleus receiver in this.receivers) { clone.AddReceiver(receiver); } return clone; } class Receiver { public INucleus nucleus; public int thingId; public string thingName; public Receiver(INucleus nucleus, int thingId, string thingName) { this.nucleus = nucleus; this.thingId = thingId; this.thingName = thingName; } } [SerializeReference] private List _receivers = new(); public List receivers { get { return _receivers; } set { _receivers = value; } } protected int[] thingIds; // every receiver can handle a thing with this id public virtual void AddReceiver(INucleus receivingNucleus) { this._receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); } public void RemoveReceiver(INucleus receiverNucleus) { this._receivers.RemoveAll(receiver => receiver == receiverNucleus); receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } private int stale = 1000; private bool _isSleeping = false; public bool isSleeping => _isSleeping; public Vector3 localPosition { set { this.stale = 0; this._isSleeping = false; this._outputValue = value; } } public float distanceResolution = 0.1f; public float directionResolution = 5; private float3 _outputValue; public float3 outputValue { get { return this._outputValue; } set { this.stale = 0; this._isSleeping = false; this._outputValue = value; } } public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; thingIds ??= new int[this._receivers.Count]; int receiverIx = 0; INucleus selectedReceiver = null; int selectedReceiverIx = 0; foreach (INucleus receiver in this.receivers) { if (thingIds[receiverIx] == thingId) { // We found an existing receiver for this thing selectedReceiver = receiver; selectedReceiverIx = receiverIx; // Do not look any further break; } else if (receiver.isSleeping) { // A sleeping receiver is not active and can therefore always be used selectedReceiver = receiver; selectedReceiverIx = receiverIx; // Look further because we may find an existing receiver for this thing } else if (selectedReceiver == null) { // If we haven't found a receiver yet, just start by taking the first selectedReceiver = receiver; selectedReceiverIx = receiverIx; } else if (selectedReceiver.isSleeping == false) { // If no existing or sleeping receiver is found, we look for // the receiver with the furthest/least interesting stimulus if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); selectedReceiver = receiver; selectedReceiverIx = receiverIx; } } receiverIx++; } // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); thingIds[selectedReceiverIx] = thingId; // if (thingName != null) // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; selectedReceiver.UpdateState(); } public void UpdateNuclei() { this.stale++; this._isSleeping = this.stale > 2; if (isSleeping) this._outputValue = Vector3.zero; } }