175 lines
5.8 KiB
C#

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<INucleus> _receivers = new();
public List<INucleus> 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;
}
}