Compare commits

..

No commits in common. "91c4500b0a1288dc674dc4a89b675b344aa861e6" and "a64ff841ac0dde229f22b4228f8cf479fea3ebff" have entirely different histories.

12 changed files with 271 additions and 399 deletions

View File

@ -4,9 +4,12 @@ using UnityEngine;
using Unity.Mathematics;
using static Unity.Mathematics.math;
[Serializable]
[System.Serializable]
public class Cluster : INucleus {
// The ScriptableObject asset from which the runtime object has been created
public readonly ClusterPrefab prefab;
public ClusterPrefab cluster { get; set; }
[SerializeField]
protected string _name;
@ -15,113 +18,17 @@ public class Cluster : INucleus {
set => _name = value;
}
#region Init
public Cluster(ClusterPrefab prefab, Cluster parent) {
// Hmm, a cluster instance can never be part of a scriptable object...(Cluster)
public Cluster(ClusterPrefab parent, ClusterPrefab prefab) {
this.prefab = prefab;
this.name = prefab.name;
this.parent = parent;
this.parent?.nuclei.Add(this);
ClonePrefab();
this.sortedNuclei = TopologicalSort(this.nuclei);
}
public Cluster(ClusterPrefab prefab, ClusterPrefab parent = null) {
this.prefab = prefab;
this.name = prefab.name;
this.cluster = parent;
if (this.cluster != null)
this.cluster.nuclei.Add(this);
ClonePrefab();
this.sortedNuclei = TopologicalSort(this.nuclei);
}
// public Cluster(ClusterPrefab parent, ClusterPrefab realPrefab) {
// this.prefab = realPrefab;
// this.name = realPrefab.name;
// this.cluster = parent;
// if (this.cluster != null)
// this.cluster.nuclei.Add(this);
// ClonePrefab();
// foreach (IReceptor nucleus in this.prefab.nuclei) {
// IReceptor clone = nucleus.CloneTo(null);
// this.dynamicNuclei.Add(clone);
// }
private void ClonePrefab() {
IReceptor[] nucleiArray = this.prefab.nuclei.ToArray();
// first clone the nuclei without their connections
foreach (IReceptor nucleus in this.prefab.nuclei)
nucleus.ShallowCloneTo(this);
IReceptor[] clonedNuclei = this.nuclei.ToArray();
// Now clone the connections
for (int nucleusIx = 0; nucleusIx < nucleiArray.Length; nucleusIx++) {
IReceptor receptor = nucleiArray[nucleusIx];
IReceptor clonedSender = clonedNuclei[nucleusIx];
if (clonedSender == null)
continue;
// Copy the receivers, which will also create the synapses
foreach (INucleus receiver in receptor.receivers) {
int ix = GetNucleusIndex(nucleiArray, receiver);
if (ix < 0)
continue;
if (clonedNuclei[ix] is not INucleus clonedReceiver)
continue;
// Find the synapse for the weight
float weight = 1;
foreach (Synapse synapse in receiver.synapses) {
if (synapse.nucleus == receptor) {
weight = synapse.weight;
break;
}
}
clonedSender.AddReceiver(clonedReceiver, weight);
}
}
}
// Sort the nuclei in a correct evaluation order
private List<IReceptor> TopologicalSort(List<IReceptor> nodes) {
Dictionary<IReceptor, int> inDegree = new();
foreach (IReceptor node in nodes)
inDegree[node] = 0; // Initialize in-degree to zero
// Calculate in-degrees
foreach (IReceptor node in nodes) {
foreach (INucleus receiver in node.receivers)
inDegree[receiver]++;
}
Queue<IReceptor> queue = new();
foreach (IReceptor node in nodes) {
if (inDegree[node] == 0) // Nodes with no dependencies
queue.Enqueue(node);
}
List<IReceptor> sortedOrder = new();
while (queue.Count > 0) {
IReceptor current = queue.Dequeue();
sortedOrder.Add(current); // Process the node
foreach (INucleus receiver in current.receivers) {
inDegree[receiver]--;
if (inDegree[receiver] == 0) // If all dependencies resolved
queue.Enqueue(receiver);
}
}
// Check for cycles in the graph
if (sortedOrder.Count != nodes.Count)
throw new InvalidOperationException("Graph is not a DAG; a cycle exists.");
return sortedOrder;
}
public virtual IReceptor Clone() {
@ -139,59 +46,6 @@ public class Cluster : INucleus {
return clone;
}
public IReceptor ShallowCloneTo(Cluster parent) {
Cluster clone = new(this.prefab, parent) {
name = this.name,
};
return clone;
}
private int GetNucleusIndex(IReceptor[] nucleiArray, IReceptor nucleus) {
for (int i = 0; i < nucleiArray.Length; i++) {
if (nucleus == nucleiArray[i])
return i;
}
return -1;
}
#endregion Init
public ClusterPrefab prefab;
public ClusterPrefab cluster { get; set; }
public Cluster parent { get; set; }
[SerializeReference]
public List<IReceptor> nuclei = new();
// the nuclei sorted using topological sorting
// to ensure that the cluster is computer in the right order
public List<IReceptor> sortedNuclei;
public List<INucleus> _inputs = null;
public virtual List<INucleus> inputs {
get {
if (this._inputs == null) {
this._inputs = new();
foreach (IReceptor receptor in this.nuclei) {
if (receptor is INucleus nucleus) {
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
this._inputs.Add(nucleus);
}
}
}
return this._inputs;
}
}
public virtual INucleus output {//=> this.nuclei[0] as INucleus;
get {
if (this.nuclei.Count > 0)
return this.nuclei[0] as INucleus;
return null;
}
}
// Not sure if this belongs here...
[SerializeReference]
private NucleusArray _array;
@ -202,14 +56,27 @@ public class Cluster : INucleus {
#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, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus, weight);
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?
@ -228,9 +95,9 @@ public class Cluster : INucleus {
set { _receivers = value; }
}
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
public virtual void AddReceiver(INucleus receivingNucleus) {
this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight);
receivingNucleus.AddSynapse(this);
}
public void RemoveReceiver(INucleus receiverNucleus) {
@ -238,6 +105,48 @@ public class Cluster : INucleus {
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
@ -262,55 +171,16 @@ public class Cluster : INucleus {
UpdateState(new float3(0, 0, 0));
}
public void UpdateState(float3 bias) {
float3 sum = bias; // new(0, 0, 0);
public void UpdateState(float3 inputValue) {
float3 sum = inputValue; // new(0, 0, 0);
//Applying the weight factors
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
}
//this.inputs[0].UpdateState(sum);
this.inputs[0].UpdateStateIsolated(sum);
foreach (IReceptor receptor in this.sortedNuclei) {
if (receptor is INucleus nucleus && nucleus != this.inputs[0])
nucleus.UpdateStateIsolated();
}
UpdateResult(this.output.outputValue);
}
public void UpdateStateIsolated() {
float3 bias = new(0,0,0);
UpdateStateIsolated(bias);
}
public void UpdateStateIsolated(float3 bias) {
float3 sum = bias; // new(0, 0, 0);
//Applying the weight factors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
}
//this.inputs[0].UpdateState(sum);
this.inputs[0].UpdateStateIsolated(sum);
foreach (IReceptor receptor in this.sortedNuclei) {
if (receptor is INucleus nucleus && nucleus != this.inputs[0])
nucleus.UpdateStateIsolated();
}
this.outputValue = 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();
// This does not work because the prefab nucleus does not have a state
this.prefab.inputs[0].UpdateState(sum);
}
public void UpdateNuclei() {
@ -318,12 +188,72 @@ public class Cluster : INucleus {
if (this.stale > 2)
_outputValue = Vector3.zero;
//foreach (IReceptor nucleus in this.prefab.nuclei)
foreach (IReceptor nucleus in this.nuclei)
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
*/
}

View File

@ -4,11 +4,18 @@ using UnityEngine;
[CreateAssetMenu(menuName = "Passer/Cluster")]
public class ClusterPrefab : ScriptableObject {
//public virtual Cluster cluster {get;set;}
// The ScriptableObject asset from which the runtime object has been created
//public Cluster asset;
[SerializeReference]
public List<IReceptor> nuclei = new();
// public List<Cluster> subClusters = new();
// public void AddSubCluster(ClusterInstance subCluster) {
// this.nuclei.Add(subCluster);
// }
public virtual INucleus output => this.nuclei[0] as INucleus;
@ -18,13 +25,10 @@ public class ClusterPrefab : ScriptableObject {
if (this._inputs == null) {
this._inputs = new();
foreach (IReceptor receptor in this.nuclei) {
if (receptor is INucleus nucleus) {
// inputs have no incoming synapses yet.
if (nucleus.synapses.Count == 0)
if (receptor is INucleus nucleus)
this._inputs.Add(nucleus);
}
}
}
return this._inputs;
}
}

View File

@ -10,7 +10,7 @@ public interface INucleus : IReceptor {
// Senders
public List<Synapse> synapses { get; }
public Synapse AddSynapse(IReceptor sender, float weight = 1.0f);
public Synapse AddSynapse(IReceptor sender);
public NucleusArray array { get; set; }
@ -20,8 +20,7 @@ public interface INucleus : IReceptor {
public void UpdateState();
public void UpdateState(float3 inputValue);
public void UpdateStateIsolated();
public void UpdateStateIsolated(float3 inputValue);
#endregion dynamic state
}
@ -34,7 +33,7 @@ public interface IReceptor {
// Receivers
public List<INucleus> receivers { get; set; }
public void AddReceiver(INucleus receiver, float weight = 1);
public void AddReceiver(INucleus receiver);
public void RemoveReceiver(INucleus receiverNucleus);
#endregion static
@ -49,7 +48,7 @@ public interface IReceptor {
#endregion dynamic
public IReceptor ShallowCloneTo(Cluster parent);
//public IReceptor CloneTo(ClusterPrefab parent);
public IReceptor Clone();
}

View File

@ -4,38 +4,35 @@ using Unity.Mathematics;
using static Unity.Mathematics.math;
[Serializable]
public class MemoryCell : Neuron, INucleus {
public class MemoryCell : Neuron {
public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) { }
public MemoryCell(Cluster parent, string name) : base(parent, name) { }
// this.parent = parent;
// this.name = name;
// this.parent?.nuclei.Add(this);
// }
public MemoryCell(ClusterPrefab cluster, string name) : base(cluster, name) {}
public override IReceptor ShallowCloneTo(Cluster newParent) {
MemoryCell clone = new(newParent, this.name) {
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
return clone;
}
#region Parameters
// Returns the memorized value weighted by time
// return lastValue * (current time - last time)
[SerializeField]
public bool deltaValue = false;
#endregion Parameters
#region State
private float3 _memorizedValue;
private float _memorizedTime;
public override void UpdateState(float3 bias) {
public override void UpdateState() {
// A memorycell does not have an activation function
float3 result = bias;
float3 result = new(0, 0, 0);
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus == this) {
float deltaTime = Time.time - this.lastTime;
synapse.weight = deltaTime;
}
result += synapse.weight * synapse.nucleus.outputValue;
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
@ -47,40 +44,14 @@ public class MemoryCell : Neuron, INucleus {
UpdateResult(result);
}
public override void UpdateStateIsolated() {
float3 bias = new(0, 0, 0);
UpdateStateIsolated(bias);
}
public override void UpdateStateIsolated(float3 bias) {
// A memorycell does not have an activation function
float3 result = bias;
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
result += synapse.weight * synapse.nucleus.outputValue;
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
}
if (this.average)
result /= n;
this.outputValue = this._memorizedValue;
// Store the result for the next time
this._memorizedValue = result;
this._memorizedTime = Time.time;
}
public override void UpdateResult(Vector3 result) {
// output value is the previous value
// if (this.deltaValue) {
// float deltaTime = Time.time - this._memorizedTime;
// this._outputValue = this._memorizedValue * deltaTime;
// }
//else
this.outputValue = this._memorizedValue;
if (this.deltaValue) {
float deltaTime = Time.time - this._memorizedTime;
this._outputValue = this._memorizedValue * deltaTime;
}
else
this._outputValue = this._memorizedValue;
// Store the result for the next time
this._memorizedValue = result;

View File

@ -88,7 +88,6 @@ public class Neuron : INucleus {
#region Runtime state (not serialized)
public ClusterPrefab cluster { get; set; }
public Cluster parent { get; set; }
#region Activation
@ -154,6 +153,7 @@ public class Neuron : INucleus {
// private bool _isSleeping = false;
// public bool isSleeping => _isSleeping;
public bool isSleeping => lengthsq(this.outputValue) == 0;
public float lastTime { get; private set; }
public void UpdateNuclei() {
this.stale++;
@ -165,11 +165,6 @@ public class Neuron : INucleus {
#endregion Runtime state
public Neuron(Cluster parent, string name) {
this.parent = parent;
this.name = name;
this.parent?.nuclei.Add(this);
}
public Neuron(ClusterPrefab parent, string name) {
this.cluster = parent;
this.name = name;
@ -180,27 +175,9 @@ public class Neuron : INucleus {
// Debug.LogError("No neuroid network");
}
// this clone the nucleus without the synapses and receivers
public virtual IReceptor ShallowCloneTo(Cluster newParent) {
Neuron clone = new(newParent, this.name) {
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
return clone;
}
public virtual IReceptor ShallowCloneTo(ClusterPrefab newParent) {
Neuron clone = new(newParent, this.name) {
array = this.array,
curve = this.curve,
curvePreset = this.curvePreset,
curveMax = this.curveMax,
average = this.average
};
return clone;
}
// public Neuron(string name) {
// this._name = name;
// }
public virtual IReceptor CloneTo(ClusterPrefab parent) {
Neuron clone = new(parent, this.name) {
@ -210,6 +187,8 @@ public class Neuron : INucleus {
curveMax = this.curveMax,
average = this.average
};
// if (clone.cluster != null)
// clone.cluster.nuclei.Add(clone);
foreach (Synapse synapse in this.synapses) {
Synapse clonedSynapse = clone.AddSynapse(synapse.nucleus);
@ -241,9 +220,9 @@ public class Neuron : INucleus {
return clone;
}
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
public virtual void AddReceiver(INucleus receivingNucleus) {
this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight);
receivingNucleus.AddSynapse(this);
}
public void RemoveReceiver(INucleus receiverNucleus) {
@ -275,25 +254,27 @@ public class Neuron : INucleus {
}
}
public Synapse AddSynapse(IReceptor sendingNucleus, float weight = 1.0f) {
Synapse synapse = new(sendingNucleus, weight);
public Synapse AddSynapse(IReceptor sendingNucleus) {
Synapse synapse = new(sendingNucleus);
this.synapses.Add(synapse);
return synapse;
}
public virtual void UpdateState() {
//UpdateState(new float3(0, 0, 0));
this.parent?.UpdateState();
UpdateState(new float3(0, 0, 0));
}
public virtual void UpdateState(float3 inputValue) {
float3 sum = inputValue;
float3 sum = inputValue;//new(0, 0, 0);
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
if (synapse.nucleus == this) {
float deltaTime = Time.time - this.lastTime;
synapse.weight = deltaTime;
}
sum += synapse.weight * synapse.nucleus.outputValue;
// Perhaps synapses should be removed when the output value goes to 0....
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
@ -324,47 +305,6 @@ public class Neuron : INucleus {
UpdateResult(result);
}
public virtual void UpdateStateIsolated() {
UpdateStateIsolated(new float3(0, 0, 0));
}
public virtual void UpdateStateIsolated(float3 bias) {
float3 sum = bias;
int n = 0;
//Applying the weight factgors
foreach (Synapse synapse in this.synapses) {
sum += synapse.weight * synapse.nucleus.outputValue;
// Perhaps synapses should be removed when the output value goes to 0....
if (lengthsq(synapse.nucleus.outputValue) != 0)
n++;
}
if (this.average && n > 0)
sum /= n;
// Activation function
Vector3 result;
switch (this.curvePreset) {
case CurvePresets.Linear:
result = sum;
break;
case CurvePresets.Sqrt:
result = normalize(sum) * System.MathF.Sqrt(length(sum));
break;
case CurvePresets.Power:
result = normalize(sum) * System.MathF.Pow(length(sum), 2);
break;
case CurvePresets.Reciprocal:
result = normalize(sum) * (1 / length(sum));
break;
default:
float activatedValue = this.curve.Evaluate(length(sum));
result = normalize(sum) * activatedValue;
break;
}
this.outputValue = result;
}
public virtual void UpdateResult(Vector3 result) {
// float d = Vector3.Distance(result, this.outputValue);
// if (d < 0.5f) {
@ -373,10 +313,7 @@ public class Neuron : INucleus {
// }
this.outputValue = result;
if (lengthsq(outputValue) != 0) {
Debug.Log($"{this.parent.name}.{this.name}: {this.outputValue}");
}
this.lastTime = Time.time;
foreach (INucleus receiver in this.receivers)
receiver.UpdateState();

View File

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;
@ -7,7 +6,6 @@ using static Unity.Mathematics.math;
public class Receptor : IReceptor {
private ClusterPrefab cluster;
private Cluster parent;
[SerializeField]
protected string _name;
@ -16,11 +14,6 @@ public class Receptor : IReceptor {
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)
@ -34,13 +27,15 @@ public class Receptor : IReceptor {
this.AddReceiver(nucleus);
}
public static Receptor CreateReceptor(Cluster cluster, string nucleusName) {
public static Receptor CreateReceptor(ClusterPrefab cluster, string nucleusName) {
if (cluster == null)
return null;
Receptor receptor = new(cluster);
foreach (INucleus nucleus in cluster.inputs) {
if (nucleus != null && nucleus.name == nucleusName) {
// Receptor receptor = new(cluster, nucleus);
// return receptor;
receptor.AddReceiver(nucleus);
}
}
@ -50,15 +45,6 @@ public class Receptor : IReceptor {
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);
@ -98,9 +84,9 @@ public class Receptor : IReceptor {
protected int[] thingIds; // every receiver can handle a thing with this id
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
public virtual void AddReceiver(INucleus receivingNucleus) {
this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight);
receivingNucleus.AddSynapse(this);
}
public void RemoveReceiver(INucleus receiverNucleus) {
@ -136,8 +122,6 @@ public class Receptor : IReceptor {
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];

View File

@ -11,20 +11,26 @@ MonoBehaviour:
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 60a957541c24c57e78018c202ebb1d9b, type: 3}
m_Name: Velocity
m_EditorClassIdentifier: Assembly-CSharp::ClusterPrefab
m_EditorClassIdentifier: Assembly-CSharp::Cluster
nuclei:
- rid: 2243601425629446539
- rid: 2243601403683012671
- rid: 2243601403683012676
references:
version: 2
RefIds:
- rid: 2243601425629446539
- rid: -2
type: {class: , ns: , asm: }
- rid: 2243601403683012671
type: {class: Neuron, ns: , asm: Assembly-CSharp}
data:
_name: Output
_synapses: []
_synapses:
- nucleus:
rid: -2
weight: 1
_receivers: []
_array:
rid: 2243601425629446540
rid: 2243601403683012672
_curvePreset: 0
curve:
serializedVersion: 2
@ -52,9 +58,51 @@ MonoBehaviour:
m_RotationOrder: 4
curveMax: 1
average: 0
- rid: 2243601425629446540
- rid: 2243601403683012672
type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
data:
_nuclei:
- rid: 2243601425629446539
- rid: 2243601403683012671
name: Output
- rid: 2243601403683012676
type: {class: Neuron, ns: , asm: Assembly-CSharp}
data:
_name: Position
_synapses: []
_receivers:
- rid: 2243601403683012671
_array:
rid: 2243601403683012677
_curvePreset: 0
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 1
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1000
value: 1000
inSlope: 1
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
curveMax: 1
average: 0
- rid: 2243601403683012677
type: {class: NucleusArray, ns: , asm: Assembly-CSharp}
data:
_nuclei:
- rid: 2243601403683012676
name: New neuron

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c61aecac62c26de4aaefb2612bcc9a5d
guid: dd622ac7ed09e70ea8edac595047ac82
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000

View File

@ -3,14 +3,14 @@ using UnityEngine;
using System;
using System.Linq;
public class ClusterPickerWindow : EditorWindow {
public class BrainPickerWindow : EditorWindow {
private Vector2 scroll;
private ClusterPrefab[] items = new ClusterPrefab[0];
private Action<ClusterPrefab> onPicked;
private string search = "";
public static void ShowPicker(Action<ClusterPrefab> onPicked, string title = "Select Cluster") {
var w = CreateInstance<ClusterPickerWindow>();
var w = CreateInstance<BrainPickerWindow>();
w.titleContent = new GUIContent(title);
w.minSize = new Vector2(360, 320);
w.onPicked = onPicked;
@ -21,7 +21,7 @@ public class ClusterPickerWindow : EditorWindow {
private void OnEnable() => RefreshList();
private void RefreshList() {
var guids = AssetDatabase.FindAssets("t:ClusterPrefab");
var guids = AssetDatabase.FindAssets("t:Cluster");
items = guids
.Select(g => AssetDatabase.LoadAssetAtPath<ClusterPrefab>(AssetDatabase.GUIDToAssetPath(g)))
.Where(b => b != null)

View File

@ -617,22 +617,22 @@ public class ClusterInspector : Editor {
}
protected virtual void AddCluster(INucleus nucleus) {
ClusterPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
BrainPickerWindow.ShowPicker(brain => OnClusterPicked(nucleus, brain), "Select Cluster");
}
private void OnClusterPicked(INucleus nucleus, ClusterPrefab prefab) {
Cluster subclusterInstance = new(prefab, this.cluster);
private void OnClusterPicked(INucleus nucleus, ClusterPrefab subCluster) {
Cluster subclusterInstance = new(this.cluster, subCluster);
//this.cluster.AddSubCluster(subclusterInstance);
//this.cluster.nuclei.Add(subclusterInstance);
subclusterInstance.AddReceiver(nucleus);
// This does not work somehow
// this.currentNucleus = subclusterInstance;
// BuildLayers();
}
private void EditCluster(Cluster subCluster) {
// May be used with storedPrefab...
//var currentActiveObject = Selection.activeObject;
Selection.activeObject = subCluster.prefab;
EditorGUIUtility.PingObject(subCluster.prefab);
var editor = Editor.CreateEditor(subCluster.prefab);
//Selection.activeObject = currentActiveObject;
}
// Connect to another nucleus in the same cluster

View File

@ -22,8 +22,8 @@ public class NanoBrainComponent_Editor : Editor {
}
public override VisualElement CreateInspectorGUI() {
//ClusterPrefab brain = Application.isPlaying ? component.brain.prefab : component.defaultBrain;
Cluster brain = component.brain;
//NanoBrainComponent component = target as NanoBrainComponent;
ClusterPrefab brain = Application.isPlaying ? component.brain : component.defaultBrain;
if (Application.isPlaying == false)
serializedObject.Update();
@ -79,7 +79,7 @@ public class NanoBrainComponent_Editor : Editor {
});
if (brain != null && board != null)
board.SetGraph(component.gameObject, brain.prefab, brain.output, inspectorContainer);
board.SetGraph(component.gameObject, brain, brain.output, inspectorContainer);
// else
// Debug.LogWarning(" No brain!");

View File

@ -1,15 +1,14 @@
using System;
using UnityEngine;
public class NanoBrainComponent : MonoBehaviour {
public ClusterPrefab defaultBrain;
private ClusterPrefab brainInstance;
[NonSerialized]
private Cluster brainInstance;
public Cluster brain {
public INucleus root => brainInstance.output;
public ClusterPrefab brain {
get {
if (brainInstance == null && defaultBrain != null) {
brainInstance = new Cluster(defaultBrain); //Instantiate(defaultBrain);
brainInstance = Instantiate(defaultBrain);
brainInstance.name = defaultBrain.name + " (Instance)";
SwarmControl sc = FindFirstObjectByType<SwarmControl>();
@ -24,7 +23,7 @@ public class NanoBrainComponent : MonoBehaviour {
}
}
public static void UpdateWeight(Cluster brain, string name, float weight) {
public static void UpdateWeight(ClusterPrefab brain, string name, float weight) {
INucleus root = brain.output;
foreach (Synapse synapse in root.synapses) {
if (synapse.nucleus.name == name) {