diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index afef229..e767ea8 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -38,15 +38,18 @@ public class GraphEditorWindow : EditorWindow { foreach (Neuroid neuroid in neuroids) { // If this neuroid is not visited while its output neuroid is visited - if (!neuronVisited.Contains(neuroid) && (neuronVisited.Contains(neuroid.outputNeuroid) || neuroid.outputNeuroid == null)) { + if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroid == null || + (neuronVisited.Contains(neuroid.outputNeuroid) && neuroid.outputNeuroid.layerIx == layerIx - 1))) { // Add it to the next layer currentLayer.neuroids.Add(neuroid); + neuroid.layerIx = layerIx; // Register it as visited neuronVisited.Add(neuroid); // Store its position Vector2Int neuroidPosition = new(layerIx, neuroidIx); neuroidPositions[neuroid] = neuroidPosition; neuroidIx++; + Debug.Log($"Layer {layerIx} neuron {neuroidIx} id {neuroid.id} {neuroid.name}"); } } @@ -84,41 +87,8 @@ public class GraphEditorWindow : EditorWindow { foreach (NeuroidLayer layer in layers) DrawLayer(layer); - // int column = 100; - // int row = 200; - // Vector3 parentPos = new(column, row, 0.1f); - // Handles.DrawSolidDisc(parentPos, Vector3.forward, 15); - - // DrawLayer(2, parentPos); } - // private void DrawLayer(int layerIx, Vector3 parentPos) { - // int column = layerIx * 100; - // int nodeCount = currentNeuroid.synapses.Count; - // float maxValue = 0; - // foreach (Synapse synapse in currentNeuroid.synapses.Values) { - // float value = synapse.value.magnitude; - // if (value > maxValue) - // maxValue = value; - // } - - // float spacing = 200f / nodeCount; // Calculate spacing - // float margin = 100 + spacing / 3; - // int i = 0; - // foreach (Synapse synapse in currentNeuroid.synapses.Values) { - // Vector3 pos = new(column, margin + i * spacing); - - // float brightness = synapse.weight / 10.0f; - // Handles.color = new Color(brightness, brightness, brightness); - // Handles.DrawLine(parentPos - Vector3.forward, pos); - - // float size = synapse.value.magnitude / maxValue * 20; - // Handles.color = Color.white; - // Handles.DrawSolidDisc(pos, Vector3.forward, size); - // i++; - // } - // } - private void DrawLayer(NeuroidLayer layer) { int column = layer.ix * 100; int nodeCount = layer.neuroids.Count; @@ -151,7 +121,7 @@ public class GraphEditorWindow : EditorWindow { float size = layerNeuroid.outputValue.magnitude / maxValue * 20; Handles.color = Color.white; Handles.DrawSolidDisc(parentPos, Vector3.forward, size); - Rect neuronRect = new(parentPos.x-size, parentPos.y-size, size*2, size*2); + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); if (neuronRect.Contains(Event.current.mousePosition)) HandleMouseHover(layerNeuroid, neuronRect); i++; @@ -167,7 +137,7 @@ public class GraphEditorWindow : EditorWindow { // Display tooltip with some offset Vector2 tooltipSize = GUI.skin.box.CalcSize(tooltip); Rect tooltipRect = new Rect(mousePosition.x + 10, mousePosition.y + 10, tooltipSize.x, tooltipSize.y); - + GUI.Box(tooltipRect, tooltip); } diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index 1650c1c..ed0c772 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -26,6 +26,8 @@ public class Neuroid { public int id; public string name; + public int layerIx; + public readonly Dictionary synapses = new(); public Vector3 outputValue; diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index e49f64e..5dfe556 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,6 +1,6 @@ using UnityEngine; -class Receptor { +public class Receptor { public SensoryNeuroid neuroid; public void SetValue(Vector3 value) { if (neuroid != null) { @@ -10,10 +10,15 @@ class Receptor { } -class SensoryNeuroid : Neuroid { +public class SensoryNeuroid : Neuroid { public Receptor receptor; - public SensoryNeuroid(NeuroidNetwork id) : base(id) { + public SensoryNeuroid(NeuroidNetwork net, int id) : base(net) { + this.name = "sensory neuroid"; + this.id = id; + this.receptor = new Receptor { + neuroid = this + }; } } \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 1f1c5d6..ec83a28 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -1,8 +1,7 @@ using UnityEngine; -public class Boid : MonoBehaviour -{ +public class Boid : MonoBehaviour { public float speed = 0.2f; public int neighbourCount = 0; public float inertia = 0.2f; @@ -20,6 +19,8 @@ public class Boid : MonoBehaviour readonly Collider[] results = new Collider[10]; + public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6]; + public NeuroidNetwork neuroidNet = new(); public Neuroid bodyVector; public Neuroid cohesion; @@ -32,15 +33,17 @@ public class Boid : MonoBehaviour public int id; - void Awake() - { + void Awake() { this.id = this.GetInstanceID(); sc = FindFirstObjectByType(); bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); + //neighbourSensor = new(neuroidNet) { name = "Neighbour", id = 879 }; + cohesion = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum }; + //cohesion.GetInputFrom(neighbourSensor); alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum }; target = new(neuroidNet) { name = "Target", mode = Neuroid.Mode.Sum }; @@ -55,8 +58,7 @@ public class Boid : MonoBehaviour totalForce.GetInputFrom(boundary, sc.boundaryForce); } - void Update() - { + void Update() { Physics.OverlapSphereNonAlloc(this.transform.position, 10, results); neighbourCount = 0; @@ -64,13 +66,11 @@ public class Boid : MonoBehaviour alignment.ResetWeights(); separation.ResetWeights(); - foreach (Collider c in results) - { + foreach (Collider c in results) { if (c == null) continue; - if (c as CapsuleCollider != null) - { + if (c as CapsuleCollider != null) { Boid neighbour = c.GetComponentInParent(); if (neighbour == null || neighbour == this) continue; @@ -79,12 +79,15 @@ public class Boid : MonoBehaviour Vector3 relativeVelocity = neighbour.velocity - this.velocity; int id = neighbour.GetInstanceID(); - + Receptor receptor = GetReceptor(id); + if (receptor != null) { + receptor.SetValue(localPosition); + } Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; // which is equivalent to -(localPosition.normalized / localPosition.magnitude) separation.SetInput(id, separationForce, sc.separationDistance); - cohesion.SetInput(id, localPosition, sc.cohesionForce); + //cohesion.SetInput(id, localPosition, sc.cohesionForce); alignment.SetInput(id, relativeVelocity, sc.alignmentForce); neighbourCount++; @@ -92,8 +95,7 @@ public class Boid : MonoBehaviour } //Vector3 spaceLocalPosition = sc.transform.InverseTransformPoint(this.transform.position); - if (!bounds.Contains(this.transform.position)) - { + if (!bounds.Contains(this.transform.position)) { Vector3 point = this.transform.position; // Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max); // // Ensure value is > 0 (but isn't this already) @@ -109,7 +111,7 @@ public class Boid : MonoBehaviour outside = direction * magnitude; boundary.SetInput(id, outside, sc.boundaryForce); - Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); + // Debug.Log($"boundary {this.transform.position} {outside} force = {outside * sc.boundaryForce}"); } Vector3 totalForceVector = totalForce.outputValue; @@ -120,11 +122,28 @@ public class Boid : MonoBehaviour this.transform.position += this.velocity * Time.deltaTime; - if (this.velocity != Vector3.zero) - { + if (this.velocity != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(this.velocity); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation } } + Receptor GetReceptor(int id) { + int availableIx = -1; + for (int i = 0; i < neighbourSensor.Length; i++) { + if (neighbourSensor[i] == null) + availableIx = i; + else if (neighbourSensor[i].id == id) + return neighbourSensor[i].receptor; + } + if (availableIx != -1) { + Debug.Log($"new receptor for {id}"); + SensoryNeuroid neuroid = new(neuroidNet, id); + cohesion.GetInputFrom(neuroid); + neighbourSensor[availableIx] = neuroid; + return neuroid.receptor; + } + return null; + } + } diff --git a/NanoBrain-Unity.slnx b/NanoBrain-Unity.slnx new file mode 100644 index 0000000..90452ad --- /dev/null +++ b/NanoBrain-Unity.slnx @@ -0,0 +1,4 @@ + + + +