diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index ad98aac..2fc6867 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -63,7 +63,9 @@ public class ClusterPrefab : ScriptableObject { public void GarbageCollection() { HashSet visitedNuclei = new(); - MarkNuclei(visitedNuclei, this.output); + foreach (Nucleus output in this.outputs) + MarkNuclei(visitedNuclei, output); + //MarkNuclei(visitedNuclei, this.output); //Debug.Log($"Garbage collection found {visitedNuclei.Count} Nuclei"); this.nuclei.RemoveAll(nucleus => nucleus is Nucleus n && visitedNuclei.Contains(n) == false); } diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index d4712bc..4018cc9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -130,7 +130,7 @@ public class ClusterInspector : Editor { void OnAddClusterOutput() { Nucleus newOutput = new Neuron(this.prefab, "New Output"); - + this.prefab.RefreshOutputs(); outputsField.choices = this.prefab.outputs.Select(output => output.name).ToList(); outputsField.value = newOutput.name; diff --git a/NucleusArray.cs b/NucleusArray.cs index 368aac3..89ae516 100644 --- a/NucleusArray.cs +++ b/NucleusArray.cs @@ -1,6 +1,8 @@ using System.Linq; using System.Collections.Generic; using UnityEngine; +using Unity.Mathematics; +using static Unity.Mathematics.math; [System.Serializable] public class NucleusArray { @@ -63,25 +65,57 @@ public class NucleusArray { public Dictionary thingReceivers = new(); - public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { - CleanupReceivers(); - if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { - // Debug.Log($"No receiver found for {thingId}"); - foreach (Nucleus receptor in this.nuclei) { - if (receptor is not Nucleus receiver) - continue; - - if (thingReceivers.ContainsValue(receiver) == false) { - // receiver is not used yet - // Debug.Log($"{thingId} -> {receiver.name}"); - thingReceivers.Add(thingId, receiver); + private Nucleus FindReceiver(int thingId, float3 inputValue) { + // No existing nucleus for this thing + float inputMagnitude = length(inputValue); + Nucleus selectedReceiver = null; + float selectedMagnitude = 0; + foreach (Nucleus receiver in this.nuclei) { + if (thingReceivers.ContainsValue(receiver) == false) { + // We found an unusued receiver + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } + // Look for the receiver with the lowest magnitude + else { + float magnitude = length(receiver.outputValue); + + if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { selectedReceiver = receiver; - break; + selectedMagnitude = length(selectedReceiver.outputValue); } } } + if (selectedReceiver != null) { + // Replace the receiver + // Find the thingId current associated with the receiver + int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; + if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) + thingReceivers.Remove(keyToRemove); + // And add the new association + thingReceivers.Add(thingId, selectedReceiver); + } + return selectedReceiver; + } + + public virtual void ProcessStimulus(int thingId, Vector3 inputValue, string thingName = null) { + CleanupReceivers(); + if (!thingReceivers.TryGetValue(thingId, out Nucleus selectedReceiver)) { + // No existing nucleus for this thing + selectedReceiver = FindReceiver(thingId, inputValue); + } if (selectedReceiver == null) - return; + return; if (thingName != null) { string baseName = selectedReceiver.name; @@ -100,10 +134,8 @@ public class NucleusArray { // Remove a thing-receiver connection when the nucleus is inactive List receiversToRemove = new(); foreach (KeyValuePair item in thingReceivers) { - if (item.Value.isSleeping) { - //Nucleus n = item.Value as Nucleus; - receiversToRemove.Add(item.Key); - } + if (item.Value.isSleeping) + receiversToRemove.Add(item.Key); } foreach (int thingId in receiversToRemove) { Nucleus selectedReceiver = thingReceivers[thingId];