diff --git a/Assets/NanoBrain/Receptor.cs b/Assets/NanoBrain/Receptor.cs index 69d3d46..1a3a0af 100644 --- a/Assets/NanoBrain/Receptor.cs +++ b/Assets/NanoBrain/Receptor.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; +using static Unity.Mathematics.math; public class Receptor : IReceptor { [SerializeField] @@ -11,10 +12,23 @@ public class Receptor : IReceptor { set => _name = value; } + class Receiver { + public INucleus nucleus; + public int thingId; + public string thingName; + public Receiver(INucleus nucleus, int thingId, string thingName) { + this.nucleus = nucleus; + this.thingId = thingId; + this.thingName = thingName; + } + } + [SerializeReference] private List _receivers = new(); public List receivers => _receivers; + protected int[] thingIds; // every receiver can handle a thing with this id + public virtual void AddReceiver(INucleus receivingNucleus) { this.receivers.Add(receivingNucleus); receivingNucleus.AddSynapse(this); @@ -25,7 +39,6 @@ public class Receptor : IReceptor { receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this); } - //public bool isSleeping => false; private int stale = 1000; private bool _isSleeping = false; @@ -42,7 +55,6 @@ public class Receptor : IReceptor { public float distanceResolution = 0.1f; public float directionResolution = 5; - //public float3 outputValue => this.localPosition; private float3 _outputValue; public float3 outputValue { get { return this._outputValue; } @@ -53,6 +65,11 @@ public class Receptor : IReceptor { } } + public Receptor(Cluster cluster) { + if (cluster != null) + cluster.nuclei.Add(this); + } + public Receptor(Cluster cluster, INucleus nucleus) { if (cluster != null) cluster.nuclei.Add(this); @@ -63,65 +80,67 @@ public class Receptor : IReceptor { 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 receptor = new(cluster, nucleus); + // return receptor; + receptor.AddReceiver(nucleus); } } - return null; + if (receptor.receivers.Count == 0) + return null; + else + return receptor; } public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) { this.localPosition = newLocalPositionVector; + thingIds ??= new int[this.receivers.Count]; + + int receiverIx = 0; INucleus selectedReceiver = null; + int selectedReceiverIx = 0; foreach (INucleus receiver in this.receivers) { - selectedReceiver = receiver; + // selectedReceiver = receiver; + // receiverIx++; + + if (thingIds[receiverIx] == thingId) { + // We found an existing receiver for this thing + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Do not look any further + break; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + // Look further because we may find an existing receiver for this thing + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + else if (selectedReceiver.isSleeping == false) { + // If no existing or sleeping receiver is found, we look for + // the receiver with the furthest/least interesting stimulus + if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) { + // Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" + + // $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} "); + selectedReceiver = receiver; + selectedReceiverIx = receiverIx; + } + } + receiverIx++; } - // selectedReceiver.thingId = thingId; + // Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}"); + thingIds[selectedReceiverIx] = thingId; // if (thingName != null) // selectedReceiver.nucleus.name = selectedReceiver.nucleus.baseName + " " + thingName; selectedReceiver.UpdateState(); - - // Perceptoid selectedPerceptoid = null; - // foreach (Perceptoid perceptoid in this.perceptei) { - // if (perceptoid.thingId == thingId) { - // // We found an existing perceptoid for this thing - // selectedPerceptoid = perceptoid; - // // Do not look any further - - // break; - // } - // else if (perceptoid.isSleeping) { - // // A sleeping perceptoid is not active and can therefore always be reused - // selectedPerceptoid = perceptoid; - // // Look further because we could find a existing perceptoid for this thing - // } - - // else if (selectedPerceptoid == null) { - // // If we haven't found a perceptoid yet, just start by taking the first - // selectedPerceptoid = perceptoid; - // } - - // else if (selectedPerceptoid.isSleeping == false) { - // // If no existing or sleeping perceptoid is found, we look for the perceptoid - // // we the furthest (least interesting) stimulus - // if (perceptoid.receptor.localPosition.magnitude < selectedPerceptoid.receptor.localPosition.magnitude) { - // Debug.Log($"{selectedPerceptoid.name} {selectedPerceptoid.receptor.localPosition.magnitude} {perceptoid.receptor.localPosition.magnitude} "); - // selectedPerceptoid = perceptoid; - // } - // } - // } - // if (selectedPerceptoid == null) { - // Debug.Log("No perceptoid selected, stimulus is ignored"); - // return; - // } - // // Debug.Log($"Stimulus {thingType} {thingId} {selectedPerceptoid.name}"); - // selectedPerceptoid.thingId = thingId; - // if (thingName != null) - // selectedPerceptoid.name = selectedPerceptoid.baseName + " " + thingName; - // selectedPerceptoid.UpdateState(); } public void UpdateNuclei() { diff --git a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs index f1109b9..0cf45e5 100644 --- a/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs +++ b/Assets/NanoBrain/VisualEditor/Editor/ClusterInspector.cs @@ -78,11 +78,12 @@ public class ClusterInspector : Editor { GameObject gameObject; private List layers = new(); private readonly Dictionary neuroidPositions = new(); + private bool expandArray = false; - Vector2 pan = Vector2.zero; + //Vector2 pan = Vector2.zero; //float zoom = 1f; - bool draggingCanvas = false; - Vector2 lastMouse; + //bool draggingCanvas = false; + //Vector2 lastMouse; ClusterWrapper currentWrapper; public GraphView() { @@ -98,9 +99,9 @@ public class ClusterInspector : Editor { Add(imguiContainer); //RegisterCallback(OnWheel); - RegisterCallback(OnMouseDown); - RegisterCallback(OnMouseMove); - RegisterCallback(OnMouseUp); + // RegisterCallback(OnMouseDown); + // RegisterCallback(OnMouseMove); + // RegisterCallback(OnMouseUp); } public void SetGraph(GameObject gameObject, Cluster brain, INucleus nucleus, VisualElement inspectorContainer) { @@ -181,19 +182,19 @@ public class ClusterInspector : Editor { } - void OnMouseDown(MouseDownEvent e) { - if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } - } - void OnMouseMove(MouseMoveEvent e) { - if (draggingCanvas) { - var delta = e.mousePosition - lastMouse; - pan += delta; - //content.style.left = pan.x; - //content.style.top = pan.y; - lastMouse = e.mousePosition; - } - } - void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } + // void OnMouseDown(MouseDownEvent e) { + // if (e.button == 2) { draggingCanvas = true; lastMouse = e.mousePosition; e.StopPropagation(); } + // } + // void OnMouseMove(MouseMoveEvent e) { + // if (draggingCanvas) { + // var delta = e.mousePosition - lastMouse; + // pan += delta; + // //content.style.left = pan.x; + // //content.style.top = pan.y; + // lastMouse = e.mousePosition; + // } + // } + // void OnMouseUp(MouseUpEvent e) { if (e.button == 2) draggingCanvas = false; } void OnIMGUI() { if (currentNucleus == null) @@ -217,8 +218,23 @@ public class ClusterInspector : Editor { // Draw selected Nucleus Handles.color = Color.white; - Handles.DrawSolidDisc(position, Vector3.forward, size + 2); - DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + if (expandArray) { + float spacing = 400f / this.currentNucleus.array.nuclei.Length; + float margin = 10 + spacing / 2; + int row = 0; + foreach (INucleus nucleus in this.currentNucleus.array.nuclei) { + Vector3 pos = new(150, margin + row * spacing, 0.0f); + Handles.color = Color.white; + //Handles.DrawLine(parentPos, pos); + + DrawNucleus(nucleus, pos, 0, size); + row++; + } + } + else { + Handles.DrawSolidDisc(position, Vector3.forward, size + 2); + DrawNucleus(this.currentNucleus, position, length(this.currentNucleus.outputValue), 20); + } } private void DrawReceivers(INucleus nucleus, Vector3 parentPos, float size) { @@ -318,18 +334,36 @@ public class ClusterInspector : Editor { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, }; - if (nucleus is Neuron neuron) { + if (nucleus is INucleus neuron) { if (neuron.array == null || neuron.array.nuclei == null || neuron.array.nuclei.Length == 0) neuron.array = new NucleusArray(neuron); - if (neuron.array.nuclei.Length > 1) { + if ((!expandArray || neuron.array.nuclei[0] != this.currentNucleus) && neuron.array.nuclei.Length > 1) { Handles.Label(labelPosition, neuron.array.nuclei.Length.ToString(), style); } + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + // if ((!expandArray || neuron.array.nuclei[0] != this.currentNucleus) && neuron.array.nuclei.Length > 1) { + // Handles.Label(labelPos, nucleus.name, style); + // } + // else { + if (expandArray && neuron.array.nuclei[0] == this.currentNucleus) { + int arrayIx = 0; + foreach (INucleus n in neuron.array.nuclei) { + if (n == neuron) + break; + arrayIx++; + } + Handles.Label(labelPos, $"{nucleus.name}[{arrayIx}]", style); + } + else + Handles.Label(labelPos, nucleus.name, style); + } + else { + style.alignment = TextAnchor.UpperCenter; + Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis + Handles.Label(labelPos, nucleus.name, style); } - - style.alignment = TextAnchor.UpperCenter; - Vector3 labelPos = position - Vector3.down * (size + 0.2f); // below disc along up axis - Handles.Label(labelPos, nucleus.name, style); Rect neuronRect = new(position.x - size, position.y - size, size * 2, size * 2); int id = GUIUtility.GetControlID(FocusType.Passive); @@ -371,7 +405,13 @@ public class ClusterInspector : Editor { } private void HandleClicked(IReceptor nucleus) { - if (nucleus is INucleus n) { + if (nucleus == this.currentNucleus) { + if (nucleus is INucleus n) { + expandArray = !expandArray; + return; + } + } + else if (nucleus is INucleus n) { this.currentNucleus = n; BuildLayers(); }