From 3cc5f56f61b892f2be19a72d99ecba0719ff80d3 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 4 Feb 2026 17:42:16 +0100 Subject: [PATCH] WIP: cloning of nucleusarrays is not working yet --- Cluster.cs | 48 ++++++++++++++++++++++++++++++-------- Editor/ClusterInspector.cs | 23 +++++++++++------- NanoBrain.cs | 19 +++++++++------ Neuron.cs | 2 +- NucleusArray.cs | 33 +++++++++++++------------- Receptor.cs | 10 +++++--- 6 files changed, 89 insertions(+), 46 deletions(-) diff --git a/Cluster.cs b/Cluster.cs index 6afd6aa..5f85b04 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; @@ -51,22 +52,22 @@ public class Cluster : INucleus { // } private void ClonePrefab() { - IReceptor[] nucleiArray = this.prefab.nuclei.ToArray(); + IReceptor[] nuclei = 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]; + for (int nucleusIx = 0; nucleusIx < nuclei.Length; nucleusIx++) { + IReceptor receptor = nuclei[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); + int ix = GetNucleusIndex(nuclei, receiver); if (ix < 0) continue; @@ -75,15 +76,42 @@ public class Cluster : INucleus { // Find the synapse for the weight float weight = 1; + NucleusArray nucleusArray = null; foreach (Synapse synapse in receiver.synapses) { - if (synapse.nucleus == receptor) { + if (synapse.nucleus == receptor) weight = synapse.weight; - break; + if (synapse.nucleus is INucleus synapseNucleus) { + if (synapseNucleus.array != null && synapseNucleus.array.nuclei.Length > 0) { + if (nucleusArray == null) { + // copy the array + nucleusArray = new NucleusArray(synapseNucleus.array.nuclei.Length, "array"); + for (int arrayIx = 0; arrayIx < synapseNucleus.array.nuclei.Length; arrayIx++) { + IReceptor arrayNucleus = synapseNucleus.array.nuclei[arrayIx]; + int ix2 = GetNucleusIndex(nuclei, arrayNucleus); + nucleusArray.nuclei[arrayIx] = clonedNuclei[ix2]; + } + } + synapseNucleus.array = nucleusArray; + } } } clonedSender.AddReceiver(clonedReceiver, weight); } + + // if (receptor is INucleus nucleus) { + // if (clonedSender is not INucleus clonedNucleus) { + // Debug.LogError("INucleus clone is not an INucleus!"); + // continue; + // } + // clonedNucleus.array = new NucleusArray(nucleus.array._nuclei.Length, "array"); + // for (int arrayIx = 0; arrayIx < nucleus.array._nuclei.Length; arrayIx++) { + // //foreach (INucleus arrayNucleus in nucleus.array.nuclei) { + // IReceptor arrayNucleus = nucleus.array._nuclei[arrayIx]; + // int ix = GetNucleusIndex(nuclei, arrayNucleus); + // clonedNucleus.array._nuclei[arrayIx] = clonedNuclei[ix]; + // } + // } } } @@ -96,13 +124,13 @@ public class Cluster : INucleus { // Calculate in-degrees foreach (IReceptor node in nodes) { foreach (INucleus receiver in node.receivers) - inDegree[receiver]++; + inDegree[receiver]++; } Queue queue = new(); foreach (IReceptor node in nodes) { if (inDegree[node] == 0) // Nodes with no dependencies - queue.Enqueue(node); + queue.Enqueue(node); } List sortedOrder = new(); @@ -119,7 +147,7 @@ public class Cluster : INucleus { // Check for cycles in the graph if (sortedOrder.Count != nodes.Count) - throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); + throw new InvalidOperationException("Graph is not a DAG; a cycle exists."); return sortedOrder; } @@ -281,7 +309,7 @@ public class Cluster : INucleus { // } public void UpdateStateIsolated() { - float3 bias = new(0,0,0); + float3 bias = new(0, 0, 0); UpdateStateIsolated(bias); } public void UpdateStateIsolated(float3 bias) { diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 69b1d25..0d84576 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -210,7 +210,7 @@ public class ClusterInspector : Editor { // Draw selected Nucleus if (expandArray) { float maxValue = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; @@ -231,7 +231,7 @@ public class ClusterInspector : Editor { Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + foreach (IReceptor nucleus in this.currentNucleus.array.nuclei) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -239,13 +239,13 @@ public class ClusterInspector : Editor { DrawNucleus(nucleus, pos, maxValue, size); row++; } - GUIStyle style = new(EditorStyles.label) { - alignment = TextAnchor.UpperCenter, - normal = { textColor = Color.white }, - fontStyle = FontStyle.Bold, - }; - Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 10); // below disc along up axis - Handles.Label(labelPos, this.currentNucleus.name, style); + // GUIStyle style = new(EditorStyles.label) { + // alignment = TextAnchor.UpperCenter, + // normal = { textColor = Color.white }, + // fontStyle = FontStyle.Bold, + // }; + // Vector3 labelPos = new Vector3(150, yMax, 0) - Vector3.down * (size + 25); // below disc along up axis + // Handles.Label(labelPos, this.currentNucleus.name, style); } else { Handles.color = Color.white; @@ -274,7 +274,12 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; + List drawnArrays = new(); foreach (INucleus receiver in nucleus.receivers) { + if (drawnArrays.Contains(receiver.array)) + continue; + drawnArrays.Add(receiver.array); + INucleus receiverNucleus = receiver; if (receiverNucleus == null) continue; diff --git a/NanoBrain.cs b/NanoBrain.cs index e368369..5fc7643 100644 --- a/NanoBrain.cs +++ b/NanoBrain.cs @@ -13,17 +13,22 @@ public class NanoBrain : MonoBehaviour { name = defaultBrain.name + " (Instance)" }; } - SwarmControl sc = FindFirstObjectByType(); - if (sc != null) { - UpdateWeight(brainInstance, "Containment", sc.containmentForce); - UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); - UpdateWeight(brainInstance, "Separation", sc.separationForce); - UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); - } + // SwarmControl sc = FindFirstObjectByType(); + // if (sc != null) { + // UpdateWeight(brainInstance, "Containment", sc.containmentForce); + // UpdateWeight(brainInstance, "Cohesion", sc.cohesionForce); + // UpdateWeight(brainInstance, "Separation", sc.separationForce); + // UpdateWeight(brainInstance, "Alignment", sc.alignmentForce); + // } return brainInstance; } } + // public void Awake() { + // brainInstance = new Cluster(defaultBrain); + // } + + public static void UpdateWeight(Cluster brain, string name, float weight) { INucleus root = brain.output; foreach (Synapse synapse in root.synapses) { diff --git a/Neuron.cs b/Neuron.cs index 270f830..6e33f4a 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -183,7 +183,7 @@ public class Neuron : INucleus { // this clone the nucleus without the synapses and receivers public virtual IReceptor ShallowCloneTo(Cluster newParent) { Neuron clone = new(newParent, this.name) { - array = this.array, + array = null, curve = this.curve, curvePreset = this.curvePreset, curveMax = this.curveMax, diff --git a/NucleusArray.cs b/NucleusArray.cs index 82a3b0e..bcccf49 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -5,16 +5,11 @@ using UnityEngine; [System.Serializable] public class NucleusArray { [SerializeReference] - private INucleus[] _nuclei; - private ClusterPrefab[] _clusters; - public IEnumerable nuclei { + private IReceptor[] _nuclei; + //private ClusterPrefab[] _clusters; + public IReceptor[] nuclei { get { - // if (_nuclei == null) - // return _clusters; - // else if (_clusters == null) - return _nuclei; - // else - // return _nuclei.Concat(_clusters); + return _nuclei; } } public string name; @@ -23,14 +18,19 @@ public class NucleusArray { this.name = nucleus.name; this._nuclei = new INucleus[1]; this._nuclei[0] = nucleus; - this._clusters = new ClusterPrefab[0]; + //this._clusters = new ClusterPrefab[0]; } public NucleusArray(ClusterPrefab cluster) { this.name = cluster.name; this._nuclei = new INucleus[0]; - this._clusters = new ClusterPrefab[1]; - this._clusters[0] = cluster; + // this._clusters = new ClusterPrefab[1]; + // this._clusters[0] = cluster; } + public NucleusArray(int size, string name) { + this.name = name; + this._nuclei = new INucleus[size]; + } + public void AddNucleus() { if (this._nuclei.Length == 0) { @@ -38,12 +38,12 @@ public class NucleusArray { return; } int newLength = this._nuclei.Length + 1; - INucleus[] newArray = new INucleus[newLength]; + IReceptor[] newArray = new INucleus[newLength]; for (int i = 0; i < this._nuclei.Length; i++) newArray[i] = this._nuclei[i]; if (this._nuclei[0] is INucleus nucleus) - newArray[newLength - 1] = (INucleus) nucleus.Clone(); + newArray[newLength - 1] = (INucleus)nucleus.Clone(); this._nuclei = newArray; } @@ -54,11 +54,12 @@ public class NucleusArray { Debug.LogWarning("Perceptoid array cannot be empty"); return; } - INucleus[] newPerceptei = new INucleus[newLength]; + IReceptor[] newPerceptei = new INucleus[newLength]; for (int i = 0; i < newLength; i++) newPerceptei[i] = this._nuclei[i]; // Delete the last perception - Neuron.Delete(this._nuclei[newLength]); + if (this._nuclei[newLength] is INucleus nucleus) + Neuron.Delete(nucleus); //this._nuclei[newLength]); this._nuclei = newPerceptei; } diff --git a/Receptor.cs b/Receptor.cs index c7b544b..cf99794 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -6,8 +6,6 @@ using static Unity.Mathematics.math; public class Receptor : IReceptor { - private ClusterPrefab cluster; - private Cluster parent; [SerializeField] protected string _name; @@ -63,6 +61,9 @@ public class Receptor : IReceptor { // return receptor; } + private ClusterPrefab cluster; + private Cluster parent; + public virtual IReceptor ShallowCloneTo(Cluster parent) { Receptor clone = new(parent); return clone; @@ -188,7 +189,9 @@ public class Receptor : IReceptor { } receiverIx++; } - Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + if (selectedReceiverIx >= thingIds.Length) + return; + thingIds[selectedReceiverIx] = thingId; if (thingName != null) { string baseName = selectedReceiver.name; @@ -197,6 +200,7 @@ public class Receptor : IReceptor { baseName = selectedReceiver.name.Substring(0, colonPos); selectedReceiver.name = baseName + ": " + thingName; } + Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); selectedReceiver.parent.UpdateStateIsolated(); }