diff --git a/Cluster.cs b/Cluster.cs index 69b9bad..3f0df80 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -84,15 +84,15 @@ public class Cluster : Nucleus { if (prefabReceptor is not Receptor prefabNucleus) continue; - if (prefabNucleus.array == null || prefabNucleus.array.nuclei == null || prefabNucleus.array.nuclei.Length == 0) + if (prefabNucleus.nucleiArray == null || prefabNucleus.nucleiArray.Length == 0) continue; Receptor clonedNucleus = clonedNuclei[nucleusIx] as Receptor; - if (prefabNucleus == prefabNucleus.array.nuclei[0]) { + if (prefabNucleus == prefabNucleus.nucleiArray[0]) { // We clone the array only for the first entry - NucleusArray clonedArray = new(prefabNucleus.array.nuclei.Length, "array"); + NucleusArray clonedArray = new(prefabNucleus.nucleiArray.Length, "array"); int arrayIx = 0; - foreach (Nucleus prefabArrayNucleus in prefabNucleus.array.nuclei) { + foreach (Nucleus prefabArrayNucleus in prefabNucleus.nucleiArray) { int arrayNucleusIx = GetNucleusIndex(prefabNuclei, prefabArrayNucleus); if (arrayNucleusIx >= 0) { Nucleus clonedArrayNucleus = clonedNuclei[arrayNucleusIx]; @@ -107,9 +107,9 @@ public class Cluster : Nucleus { } else { // The others will refer to the array created for the first nucleus in the array - int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.array.nuclei[0]); + int firstNucleusIx = GetNucleusIndex(prefabNuclei, prefabNucleus.nucleiArray[0]); Receptor clonedFirstNucleus = clonedNuclei[firstNucleusIx] as Receptor; - clonedNucleus.array = clonedFirstNucleus.array; + clonedNucleus.nucleiArray = clonedFirstNucleus.nucleiArray; } } } diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index f5bb1ad..3df0d35 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -65,6 +65,21 @@ public class ClusterReceptor : Cluster, IReceptor { set { _array = value; } } + //[SerializeReference] + //private Nucleus[] _nucleusArray; + public Nucleus[] nucleiArray { + get { return _array.nuclei; } + set { _array.nuclei = value; } + } + + public void AddReceptorElement(ClusterPrefab prefab) { + this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); + } + + public void RemoveReceptorElement() { + this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); + } + public override void UpdateStateIsolated() { float3 sum = this.bias; diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index d8319c6..b175124 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -300,13 +300,13 @@ public class ClusterInspector : Editor { // else if (this.currentNucleus is IReceptor receptor1) { float maxValue = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { + foreach (Nucleus nucleus in receptor1.nucleiArray) { float value = length(nucleus.outputValue); if (value > maxValue) maxValue = value; } - float spacing = 400f / receptor1.array.nuclei.Count(); + float spacing = 400f / receptor1.nucleiArray.Count(); float margin = 10 + spacing / 2; float xMin = 150 - size; float xMax = 150 + size; @@ -321,7 +321,7 @@ public class ClusterInspector : Editor { Handles.color = Color.black; Handles.DrawAAConvexPolygon(verts); int row = 0; - foreach (Nucleus nucleus in receptor1.array.nuclei) { + foreach (Nucleus nucleus in receptor1.nucleiArray) { Vector3 pos = new(150, margin + row * spacing, 0.0f); Handles.color = Color.white; // The selected nucleus highlight ring @@ -387,12 +387,12 @@ public class ClusterInspector : Editor { float margin = 10 + spacing / 2; int row = 0; - List drawnArrays = new(); + List drawnArrays = new(); foreach (Nucleus receiver in receivers) { if (receiver is Receptor receptor) { - if (drawnArrays.Contains(receptor.array)) + if (drawnArrays.Contains(receptor.nucleiArray)) continue; - drawnArrays.Add(receptor.array); + drawnArrays.Add(receptor.nucleiArray); } Nucleus receiverNucleus = receiver; @@ -415,17 +415,17 @@ public class ClusterInspector : Editor { // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; int neuronCount = 0; - List drawnArrays = new(); + List drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Receptor receptor) { - if (drawnArrays.Contains(receptor.array)) + if (drawnArrays.Contains(receptor.nucleiArray)) continue; - drawnArrays.Add(receptor.array); + drawnArrays.Add(receptor.nucleiArray); } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { - if (drawnArrays.Contains(clusterReceptor.array)) + if (drawnArrays.Contains(clusterReceptor.nucleiArray)) continue; - drawnArrays.Add(clusterReceptor.array); + drawnArrays.Add(clusterReceptor.nucleiArray); } float value = length(synapse.nucleus.outputValue) * synapse.weight; // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); @@ -442,14 +442,14 @@ public class ClusterInspector : Editor { drawnArrays = new(); foreach (Synapse synapse in nucleus.synapses) { if (synapse.nucleus is Receptor neuron) { - if (drawnArrays.Contains(neuron.array)) + if (drawnArrays.Contains(neuron.nucleiArray)) continue; - drawnArrays.Add(neuron.array); + drawnArrays.Add(neuron.nucleiArray); } else if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) { - if (drawnArrays.Contains(clusterReceptor.array)) + if (drawnArrays.Contains(clusterReceptor.nucleiArray)) continue; - drawnArrays.Add(clusterReceptor.array); + drawnArrays.Add(clusterReceptor.nucleiArray); } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; @@ -521,7 +521,7 @@ public class ClusterInspector : Editor { style.normal.textColor = Color.black; else style.normal.textColor = Color.white; - Handles.Label(labelPosition, receptor1.array.nuclei.Length.ToString(), style); + Handles.Label(labelPosition, receptor1.nucleiArray.Length.ToString(), style); style.normal.textColor = Color.white; } } @@ -704,15 +704,17 @@ public class ClusterInspector : Editor { } if (this.currentNucleus is Receptor receptor1) { EditorGUILayout.BeginHorizontal(); - EditorGUILayout.IntField("Array size", receptor1.array.nuclei.Count()); + EditorGUILayout.IntField("Array size", receptor1.nucleiArray.Count()); if (GUILayout.Button("Add")) { Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - receptor1.array.AddNucleus(this.prefab); + //receptor1.array.AddNucleus(this.prefab); + receptor1.AddReceptorElement(this.prefab); anythingChanged = true; } if (GUILayout.Button("Del")) { Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - receptor1.array.RemoveNucleus(); + //receptor1.array.RemoveNucleus(); + receptor1.RemoveReceptorElement(); anythingChanged = true; } EditorGUILayout.EndHorizontal(); @@ -754,7 +756,7 @@ public class ClusterInspector : Editor { anythingChanged |= newBias != this.currentNucleus.bias; this.currentNucleus.bias = newBias; - NucleusArray array = null; + Nucleus[] array = null; if (this.currentNucleus.synapses.Count > 0) { Synapse[] synapses = this.currentNucleus.synapses.ToArray(); foreach (Synapse synapse in synapses) { @@ -762,16 +764,16 @@ public class ClusterInspector : Editor { continue; if (array != null) { - if (array.nuclei.Contains(synapse.nucleus)) + if (array.Contains(synapse.nucleus)) continue; - if (array.nuclei.Contains(synapse.nucleus.parent)) + if (array.Contains(synapse.nucleus.parent)) continue; } else { if (synapse.nucleus.parent is ClusterReceptor clusterReceptor) - array = clusterReceptor.array; + array = clusterReceptor.nucleiArray; else if (synapse.nucleus is Receptor receptor2) // && receptor2.array != null && receptor2.array.nuclei.Length > 1) - array = receptor2.array; + array = receptor2.nucleiArray; } EditorGUILayout.Space(); @@ -832,7 +834,7 @@ public class ClusterInspector : Editor { EditorGUILayout.EndHorizontal(); } if (neuron is Receptor receptor2) { - if (receptor2.array == null || receptor2.array.nuclei == null || receptor2.array.nuclei.Count() == 0) + if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) receptor2.array = new NucleusArray(neuron); } } @@ -877,7 +879,7 @@ public class ClusterInspector : Editor { } else { if (this.currentNucleus is Receptor receptor1) { - foreach (Nucleus nucleus in receptor1.array.nuclei) { + foreach (Nucleus nucleus in receptor1.nucleiArray) { Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); diff --git a/IReceptor.cs b/IReceptor.cs index 18c3c35..08bb505 100644 --- a/IReceptor.cs +++ b/IReceptor.cs @@ -3,9 +3,49 @@ using UnityEngine; public interface IReceptor { public string GetName(); - public NucleusArray array { - get; set; + // public NucleusArray array { + // get; set; + // } + public Nucleus[] nucleiArray { get; set; } + + public void AddReceptorElement(ClusterPrefab prefab); + public void RemoveReceptorElement(); + + public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null); +} + +public static class IReceptorHelpers { + public static Nucleus[] AddReceptorElement(Nucleus[] nucleiArray, ClusterPrefab prefab) { + if (nucleiArray.Length == 0) { + Debug.LogError("Empty perceptoid array, cannot add"); + return null; + } + int newLength = nucleiArray.Length + 1; + Nucleus[] newArray = new Nucleus[newLength]; + + for (int i = 0; i < nucleiArray.Length; i++) + newArray[i] = nucleiArray[i]; + if (nucleiArray[0] is Nucleus nucleus) { + newArray[newLength - 1] = nucleus.Clone(prefab); + newArray[newLength - 1].name += $": {newLength - 1}"; + } + + return newArray; } - public void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName =null); + public static Nucleus[] RemoveReceptorElement(Nucleus[] nucleiArray) { + int newLength = nucleiArray.Length - 1; + if (newLength == 0) { + Debug.LogWarning("Perceptoid array cannot be empty"); + return null; + } + Nucleus[] newPerceptei = new Nucleus[newLength]; + for (int i = 0; i < newLength; i++) + newPerceptei[i] = nucleiArray[i]; + // Delete the last perception + if (nucleiArray[newLength] is Nucleus nucleus) + Neuron.Delete(nucleus); //this._nuclei[newLength]); + + return newPerceptei; + } } \ No newline at end of file diff --git a/Neuron.cs b/Neuron.cs index 31f033a..7822ba8 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -295,7 +295,7 @@ public class Neuron : Nucleus { public virtual void RemoveReceiver(Nucleus receiverToRemove) { if (this is IReceptor receptor) { - foreach (Nucleus element in receptor.array.nuclei) { + foreach (Nucleus element in receptor.nucleiArray) { if (element is Neuron neuron) { neuron._receivers.RemoveAll(receiver => receiver == receiverToRemove); receiverToRemove.synapses.RemoveAll(synapse => synapse.nucleus == neuron); diff --git a/NucleusArray.cs b/NucleusArray.cs index 2f8fe2d..b3651df 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -12,6 +12,9 @@ public class NucleusArray { get { return _nuclei; } + set { + _nuclei = value; + } } public NucleusArray(Nucleus nucleus) { @@ -68,7 +71,7 @@ public class NucleusArray { float inputMagnitude = length(inputValue); Nucleus selectedReceiver = null; float selectedMagnitude = 0; - foreach (Nucleus receiver in this.nuclei) { + foreach (Nucleus receiver in this._nuclei) { if (thingReceivers.ContainsValue(receiver) == false) { // We found an unusued receiver thingReceivers.Add(thingId, receiver); diff --git a/Receptor.cs b/Receptor.cs index 36e33ca..2547f36 100644 --- a/Receptor.cs +++ b/Receptor.cs @@ -5,12 +5,12 @@ using static Unity.Mathematics.math; [System.Serializable] public class Receptor : Neuron, IReceptor { public Receptor(Cluster parent, string name) : base(parent, name) { - this.array ??= new NucleusArray(this); + this.array = new NucleusArray(this); if (this.name.IndexOf(":") < 0) this.name += ": 0"; } public Receptor(ClusterPrefab prefab, string name) : base(prefab, name) { - this.array ??= new NucleusArray(this); + this.array = new NucleusArray(this); } public string GetName() { @@ -26,7 +26,7 @@ public class Receptor : Neuron, IReceptor { } public override Nucleus Clone(ClusterPrefab prefab) { Receptor clone = new(prefab, name) { - array = this.array + array = this._array }; CloneFields(clone); // Adding receivers will also add synapses to the receivers @@ -39,12 +39,24 @@ public class Receptor : Neuron, IReceptor { [SerializeReference] private NucleusArray _array; public NucleusArray array { - get { return _array; } set { _array = value; } } + public Nucleus[] nucleiArray { + get { return _array.nuclei; } + set { _array.nuclei = value; } + } + + public void AddReceptorElement(ClusterPrefab prefab) { + this.nucleiArray = IReceptorHelpers.AddReceptorElement(this.nucleiArray, prefab); + } + + public void RemoveReceptorElement() { + this.nucleiArray = IReceptorHelpers.RemoveReceptorElement(this.nucleiArray); + } + public virtual void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { - foreach (Nucleus element in this.array.nuclei) { + foreach (Nucleus element in this._array.nuclei) { if (element is Neuron neuron) { neuron.AddReceiver(receiverToAdd, weight); } @@ -65,7 +77,7 @@ public class Receptor : Neuron, IReceptor { } public virtual void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - this.array ??= new NucleusArray(this.parent); - this.array.ProcessStimulus(thingId, inputValue, thingName); + this._array ??= new NucleusArray(this.parent); + this._array.ProcessStimulus(thingId, inputValue, thingName); } } \ No newline at end of file