195 lines
6.4 KiB
C#
195 lines
6.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Unity.Mathematics;
|
|
using static Unity.Mathematics.math;
|
|
|
|
public class Receptor : IReceptor {
|
|
|
|
private ClusterPrefab cluster;
|
|
private Cluster parent;
|
|
|
|
[SerializeField]
|
|
protected string _name;
|
|
public virtual string name {
|
|
get => _name;
|
|
set => _name = value;
|
|
}
|
|
|
|
public Receptor(Cluster parent) {
|
|
this.parent = parent;
|
|
if (parent != null)
|
|
parent.nuclei.Add(this);
|
|
}
|
|
public Receptor(ClusterPrefab cluster) {
|
|
this.cluster = cluster;
|
|
if (cluster != null)
|
|
cluster.nuclei.Add(this);
|
|
}
|
|
|
|
public Receptor(ClusterPrefab cluster, INucleus nucleus) {
|
|
this.cluster = cluster;
|
|
if (cluster != null)
|
|
cluster.nuclei.Add(this);
|
|
this.AddReceiver(nucleus);
|
|
}
|
|
|
|
public static Receptor CreateReceptor(Cluster cluster, string nucleusName) {
|
|
if (cluster == null)
|
|
return null;
|
|
|
|
//Receptor receptor = new(cluster.prefab);
|
|
Receptor receptor = new(cluster);
|
|
//foreach (INucleus nucleus in cluster.prefab.inputs) {
|
|
foreach (INucleus nucleus in cluster.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 ShallowCloneTo(Cluster parent) {
|
|
Receptor clone = new(parent);
|
|
return clone;
|
|
}
|
|
public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) {
|
|
Receptor clone = new(parent);
|
|
return clone;
|
|
}
|
|
|
|
public virtual IReceptor CloneTo(ClusterPrefab 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;
|
|
if (this._receivers == null)
|
|
return;
|
|
|
|
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;
|
|
}
|
|
} |