286 lines
8.8 KiB
C#
286 lines
8.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Unity.Mathematics;
|
|
using static Unity.Mathematics.math;
|
|
|
|
[System.Serializable]
|
|
public class Cluster : INucleus {
|
|
// The ScriptableObject asset from which the runtime object has been created
|
|
[SerializeField]
|
|
public ClusterPrefab prefab;
|
|
|
|
public ClusterPrefab cluster { get; set; }
|
|
|
|
[SerializeField]
|
|
protected string _name;
|
|
public virtual string name {
|
|
get => _name;
|
|
set => _name = value;
|
|
}
|
|
|
|
public Cluster(ClusterPrefab prefab) {
|
|
this.prefab = UnityEngine.Object.Instantiate(prefab);
|
|
this.name = prefab.name;
|
|
this.cluster = null;
|
|
if (this.cluster != null)
|
|
this.cluster.nuclei.Add(this);
|
|
}
|
|
|
|
// Hmm, a cluster instance can never be part of a scriptable object...(Cluster)
|
|
public Cluster(ClusterPrefab parent, ClusterPrefab prefab) {
|
|
this.prefab = prefab.Clone(); //UnityEngine.Object.Instantiate(prefab);
|
|
this.name = prefab.name;
|
|
this.cluster = parent;
|
|
if (this.cluster != null)
|
|
this.cluster.nuclei.Add(this);
|
|
|
|
// foreach (IReceptor nucleus in this.prefab.nuclei) {
|
|
// IReceptor clone = nucleus.CloneTo(null);
|
|
// this.dynamicNuclei.Add(clone);
|
|
// }
|
|
}
|
|
|
|
public virtual IReceptor Clone() {
|
|
Neuron clone = new(this.cluster, this.name) {
|
|
array = this.array,
|
|
};
|
|
|
|
foreach (Synapse synapse in this.synapses) {
|
|
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
|
|
clonedSynapse.weight = synapse.weight;
|
|
}
|
|
foreach (INucleus receiver in this.receivers) {
|
|
clone.AddReceiver(receiver);
|
|
}
|
|
return clone;
|
|
}
|
|
|
|
public INucleus output => prefab.output;
|
|
|
|
// Not sure if this belongs here...
|
|
[SerializeReference]
|
|
private NucleusArray _array;
|
|
public NucleusArray array {
|
|
get { return _array; }
|
|
set { _array = value; }
|
|
}
|
|
|
|
#region Synapses
|
|
|
|
// class ClusterSynapse : Synapse {
|
|
// public IReceptor receptor;
|
|
// public ClusterSynapse(IReceptor nucleus, INucleus receptor, float weight = 1.0f) : base(nucleus, weight) {
|
|
// this.receptor = receptor;
|
|
// }
|
|
// }
|
|
[SerializeField]
|
|
private List<Synapse> _synapses = new();
|
|
public List<Synapse> synapses => _synapses;
|
|
|
|
public Synapse AddSynapse(IReceptor sendingNucleus) {
|
|
Synapse synapse = new(sendingNucleus); //, this.prefab.inputs[0]);
|
|
this._synapses.Add(synapse);
|
|
return synapse;
|
|
// else {
|
|
// INucleus receptor = (INucleus)this.prefab.nuclei.Find(nucleus => nucleus is INucleus n && nucleus.name == nucleusName);
|
|
// ClusterSynapse synapse = new(sendingNucleus, receptor);
|
|
// receptor.AddSynapse(sendingNucleus);
|
|
// }
|
|
// // Add synapse to which neuron?
|
|
// return null;
|
|
}
|
|
|
|
// Does this even exist already?
|
|
public void RemoveSynapse() {
|
|
|
|
}
|
|
|
|
#endregion Synapses
|
|
|
|
#region Receivers
|
|
|
|
[SerializeReference]
|
|
private List<INucleus> _receivers = new();
|
|
public List<INucleus> receivers {
|
|
get { return _receivers; }
|
|
set { _receivers = value; }
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// public void AddReceiver(INucleus receivingNucleus) {
|
|
// int newLength = this._receivers.Count + 1;
|
|
// INucleus[] newReceivers = new INucleus[newLength];
|
|
|
|
// // Copy the existing receivers
|
|
// for (int ix = 0; ix < this._receivers.Count; ix++)
|
|
// newReceivers[ix] = this._receivers[ix];
|
|
// // Add the new receivers
|
|
// newReceivers[this._receivers.Count] = receivingNucleus;
|
|
// // Replace the receivers with the new receivers
|
|
// this._receivers = new(newReceivers);
|
|
|
|
// receivingNucleus.AddSynapse(this);
|
|
// }
|
|
|
|
// public void RemoveReceiver(INucleus receivingNucleus) {
|
|
// Debug.Log("Clusterinstance. remote receiver");
|
|
// int newLength = this._receivers.Count - 1;
|
|
// if (newLength < 0)
|
|
// // Array was empty, so we cannot remove anything
|
|
// return;
|
|
|
|
// INucleus[] newReceivers = new INucleus[newLength];
|
|
|
|
// int newIx = 0;
|
|
// // Copy all receivers except receivingNucleus
|
|
// for (int ix = 0; ix < this._receivers.Count; ix++) {
|
|
// if (this._receivers[ix] == receivingNucleus)
|
|
// // skip the receiver we want to remote
|
|
// continue;
|
|
|
|
// if (newIx >= newLength)
|
|
// // We want to copy more elements than expected
|
|
// // the receivingNucleus is not found
|
|
// // and the original array is returned
|
|
// return;
|
|
// newReceivers[newIx] = this._receivers[ix];
|
|
// newIx++;
|
|
// }
|
|
// this._receivers = new(newReceivers);
|
|
// }
|
|
|
|
#endregion Receivers
|
|
|
|
#region Runtime
|
|
|
|
[NonSerialized]
|
|
private int stale = 1000;
|
|
public bool isSleeping => lengthsq(this.outputValue) == 0;
|
|
|
|
[NonSerialized]
|
|
protected float3 _outputValue;
|
|
public virtual float3 outputValue {
|
|
get { return _outputValue; }
|
|
set {
|
|
this.stale = 0;
|
|
_outputValue = value;
|
|
}
|
|
}
|
|
|
|
#region Update
|
|
|
|
public virtual void UpdateState() {
|
|
UpdateState(new float3(0, 0, 0));
|
|
}
|
|
|
|
public void UpdateState(float3 inputValue) {
|
|
float3 sum = inputValue; // new(0, 0, 0);
|
|
|
|
//Applying the weight factgors
|
|
foreach (Synapse synapse in this.synapses) {
|
|
sum += synapse.weight * synapse.nucleus.outputValue;
|
|
}
|
|
|
|
// This does not work because the prefab nucleus does not have a state
|
|
this.prefab.inputs[0].UpdateState(sum);
|
|
//this._outputValue = this.output.outputValue;
|
|
UpdateResult(this.output.outputValue);
|
|
}
|
|
|
|
public virtual void UpdateResult(Vector3 result) {
|
|
// float d = Vector3.Distance(result, this.outputValue);
|
|
// if (d < 0.5f) {
|
|
// //Debug.Log($"insignificant update: {d}");
|
|
// return;
|
|
// }
|
|
|
|
this.outputValue = result;
|
|
foreach (INucleus receiver in this.receivers)
|
|
receiver.UpdateState();
|
|
}
|
|
|
|
public void UpdateNuclei() {
|
|
this.stale++;
|
|
if (this.stale > 2)
|
|
_outputValue = Vector3.zero;
|
|
|
|
foreach (IReceptor nucleus in this.prefab.nuclei)
|
|
nucleus.UpdateNuclei();
|
|
}
|
|
|
|
#endregion Update
|
|
|
|
#endregion Runtime
|
|
|
|
/*
|
|
[SerializeField]
|
|
private List<IReceptor> _dynamicNuclei;
|
|
public List<IReceptor> dynamicNuclei {// = new();
|
|
get {
|
|
if (_dynamicNuclei == null) {
|
|
this._dynamicNuclei = new();
|
|
foreach (IReceptor nucleus in this.prefab.nuclei) {
|
|
IReceptor clone = nucleus.CloneTo(null);
|
|
this._dynamicNuclei.Add(clone);
|
|
}
|
|
}
|
|
return this._dynamicNuclei;
|
|
}
|
|
}
|
|
|
|
public List<INucleus> _inputs = null;
|
|
public List<INucleus> inputs {
|
|
get {
|
|
this._inputs = new();
|
|
if (this.dynamicNuclei != null) {
|
|
foreach (IReceptor receptor in this.dynamicNuclei) {
|
|
if (receptor is INucleus nucleus)
|
|
this._inputs.Add(nucleus);
|
|
}
|
|
}
|
|
return this._inputs;
|
|
}
|
|
}
|
|
|
|
public INucleus output => this.dynamicNuclei[0] as INucleus;
|
|
|
|
public float3 outputValue => this.output.outputValue;
|
|
|
|
|
|
public IReceptor CloneTo(ClusterPrefab parent) {
|
|
Cluster clone = new(parent, this.prefab);
|
|
return clone;
|
|
}
|
|
public IReceptor Clone() {
|
|
Cluster clone = new(this.cluster, this.prefab);
|
|
return clone;
|
|
}
|
|
|
|
#region Properties
|
|
|
|
public string name {
|
|
get { return prefab.name; }
|
|
set { prefab.name = value; }
|
|
}
|
|
|
|
public bool isSleeping => lengthsq(this.outputValue) == 0;
|
|
|
|
public NucleusArray array { get; set; }
|
|
|
|
#endregion Properties
|
|
|
|
|
|
*/
|
|
|
|
}
|