From 145e033d4c3389f729e2fd0096805108581619ca Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 3 Dec 2025 10:16:36 +0100 Subject: [PATCH] Simplified synapses, NanoBrain component --- Assembly-CSharp-Editor.csproj | 1 + Assembly-CSharp.csproj | 1 + Assets/NanoBrain/Editor/NanoBrain_Editor.cs | 203 ++++++++++++++++++ .../NanoBrain/Editor/NanoBrain_Editor.cs.meta | 2 + Assets/NanoBrain/Editor/NeuroidWindow.cs | 21 +- Assets/NanoBrain/NanoBrain.cs | 19 ++ Assets/NanoBrain/NanoBrain.cs.meta | 2 + Assets/NanoBrain/Neuroid.cs | 103 ++++----- Assets/NanoBrain/Nucleus.cs | 2 +- Assets/NanoBrain/Perception.cs | 10 +- Assets/NanoBrain/SensoryNeuroid.cs | 80 ++++--- Assets/Scenes/Boids/Boids.unity | 2 +- Assets/Scenes/Boids/Scripts/Boid.cs | 22 +- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 3 +- .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 5 +- 15 files changed, 364 insertions(+), 112 deletions(-) create mode 100644 Assets/NanoBrain/Editor/NanoBrain_Editor.cs create mode 100644 Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta create mode 100644 Assets/NanoBrain/NanoBrain.cs create mode 100644 Assets/NanoBrain/NanoBrain.cs.meta diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj index 584a691..23e17fc 100644 --- a/Assembly-CSharp-Editor.csproj +++ b/Assembly-CSharp-Editor.csproj @@ -48,6 +48,7 @@ + diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index cc63681..06d6dd6 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -50,6 +50,7 @@ + diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs new file mode 100644 index 0000000..39d8287 --- /dev/null +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs @@ -0,0 +1,203 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +[CustomEditor(typeof(NanoBrain))] +public class NanoBrain_Editor : Editor { + private Nucleus currentNucleus; + private List layers = new(); + private Dictionary neuroidPositions = new(); + + #region Start + + private void OnEnable() { + SelectNeuron(); + } + + private void SelectNeuron() { + GameObject selectedObject = ((NanoBrain)target).gameObject; + if (!selectedObject.TryGetComponent(out Boid boid)) + return; + + Neuroid neuroid = boid.totalForce; + this.currentNucleus = neuroid; + + BuildLayers(); + Debug.Log($"Layercount = {this.layers.Count}"); + } + + #endregion Start + + #region Update + + public override void OnInspectorGUI() { + DrawGraph(); + + DrawDefaultInspector(); + } + + private void BuildLayers() { + // A temporary list to track what's been added to layers + this.layers = new(); + int layerIx = 0; + + Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; + NeuroidLayer currentLayer = new() { ix = layerIx }; + + foreach (Neuroid outputNeuroid in selectedNucleus.outputNeuroids) { + if (outputNeuroid != null) { + AddToLayer(currentLayer, outputNeuroid); + Debug.Log($"layer {layerIx} nucleus {outputNeuroid.name}"); + } + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + layerIx++; + currentLayer = new() { ix = layerIx }; + } + + AddToLayer(currentLayer, selectedNucleus); + this.layers.Add(currentLayer); + Debug.Log($"layer {layerIx} nucleus {selectedNucleus.name}"); + + layerIx++; + currentLayer = new() { ix = layerIx }; + + foreach (Nucleus input in selectedNucleus.synapses.Keys) { + AddToLayer(currentLayer, input); + Debug.Log($"layer {layerIx} nucleus {input.name}"); + } + if (currentLayer.neuroids.Count > 0) { + this.layers.Add(currentLayer); + } + } + + private void AddToLayer(NeuroidLayer layer, Nucleus nucleus) { + layer.neuroids.Add(nucleus); + nucleus.layerIx = layer.ix; + // Store its position + Vector2Int neuroidPosition = new(layer.ix, layer.neuroids.Count - 1); + neuroidPositions[nucleus] = neuroidPosition; + + } + + private void DrawGraph() { + if (currentNucleus == null) + return; + Rect outer = EditorGUILayout.GetControlRect(false, 400); + GUI.BeginGroup(outer); + foreach (NeuroidLayer layer in layers) + DrawLayer(layer); + GUI.EndGroup(); + } + + private void DrawLayer(NeuroidLayer layer) { + int nodeCount = layer.neuroids.Count; + float maxValue = 0; + foreach (Nucleus nucleus in layer.neuroids) { + if (nucleus is Neuroid neuroid) { + float value = neuroid.outputValue.magnitude; + if (value > maxValue) + maxValue = value; + } + } + float spacing = 400f / nodeCount; + float margin = 10 + spacing / 2; + foreach (Nucleus layerNucleus in layer.neuroids) { + if (layerNucleus is Neuroid layerNeuroid) { + Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; + Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); + + int i = 0; + float inputSpacing = 400f / layerNeuroid.synapses.Count; + float inputMargin = 10 + inputSpacing / 2; + // foreach (Synapse synapse in layerNeuroid.synapses.Values) { + // if (synapse.neuroid != null) { + // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + + // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + if (neuroid != null) { + if (this.neuroidPositions.ContainsKey(neuroid)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; + if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { + Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); + + float brightness = synapse.weight / 10.0f; + Handles.color = new Color(brightness, brightness, brightness); + Handles.DrawLine(parentPos, pos); + } + } + } + } + + float size = 20; + if (layerNeuroid.IsStale()) + Handles.color = Color.black; + else { + float brightness = layerNeuroid.outputValue.magnitude / maxValue; + Handles.color = new Color(brightness, brightness, brightness); + } + Handles.DrawSolidDisc(parentPos, Vector3.forward, size); + Vector3 labelPos = parentPos - Vector3.down * (size + 0.2f); // below disc along up axis + GUIStyle style = new GUIStyle(EditorStyles.label) { + alignment = TextAnchor.UpperCenter, + normal = { textColor = Color.white }, + fontStyle = FontStyle.Bold + }; + Handles.Label(labelPos, layerNeuroid.name, style); + + Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2); + int id = GUIUtility.GetControlID(FocusType.Passive); + Event e = Event.current; + EventType et = e.GetTypeForControl(id); + if (e != null && neuronRect.Contains(e.mousePosition)) { + HandleMouseHover(layerNeuroid, neuronRect); + // Process click + Debug.Log($"{et}"); + if (et == EventType.MouseDown && e.button == 0) { + // Consume the event so the scene doesn't also handle it + e.Use(); + HandleDiscClicked(layerNeuroid); + } + } + i++; + } + } + } + + private void HandleMouseHover(Neuroid neuroid, Rect rect) { + GUIContent tooltip; + if (neuroid is SensoryNeuroid sensoryNeuroid) { + tooltip = new( + $"{sensoryNeuroid.name}" + + $"\nThing {sensoryNeuroid.receptor.thingId}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + else { + tooltip = new( + $"{neuroid.name}" + + $"\nsynapse count {neuroid.synapses.Count}" + + $"\nValue: {neuroid.outputValue}" + + $"\nStale: {neuroid.stale}"); + } + + Vector2 mousePosition = Event.current.mousePosition; + + // 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); + } + + private void HandleDiscClicked(Nucleus nucleus) { + this.currentNucleus = nucleus; + BuildLayers(); + } + + #endregion Update +} diff --git a/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta new file mode 100644 index 0000000..ebb08bb --- /dev/null +++ b/Assets/NanoBrain/Editor/NanoBrain_Editor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2299b68d073cc5c31915f591deb79ddc \ No newline at end of file diff --git a/Assets/NanoBrain/Editor/NeuroidWindow.cs b/Assets/NanoBrain/Editor/NeuroidWindow.cs index 72f9a9b..62db660 100644 --- a/Assets/NanoBrain/Editor/NeuroidWindow.cs +++ b/Assets/NanoBrain/Editor/NeuroidWindow.cs @@ -36,6 +36,8 @@ public class GraphEditorWindow : EditorWindow { int layerIx = 0; Nucleus selectedNucleus = this.currentNucleus; + if (selectedNucleus == null) + return; NeuroidLayer currentLayer = new() { ix = layerIx }; foreach (Neuroid outputNeuroid in selectedNucleus.outputNeuroids) { @@ -58,9 +60,10 @@ public class GraphEditorWindow : EditorWindow { currentLayer = new() { ix = layerIx }; int six = 0; - foreach (Synapse synapse in selectedNucleus.synapses.Values) { - Debug.Log($"Synapse {six}"); - Nucleus input = synapse.neuroid; + // foreach (Synapse synapse in selectedNucleus.synapses.Values) { + // Debug.Log($"Synapse {six}"); + // Nucleus input = synapse.neuroid; + foreach ((Nucleus input, Synapse synapse) in selectedNucleus.synapses) { if (input != null) { AddToLayer(currentLayer, input); Debug.Log($"layer {layerIx} nucleus {input.name}"); @@ -172,11 +175,15 @@ public class GraphEditorWindow : EditorWindow { int i = 0; float inputSpacing = 400f / layerNeuroid.synapses.Count; float inputMargin = 100 + inputSpacing / 2; - foreach (Synapse synapse in layerNeuroid.synapses.Values) { - if (synapse.neuroid != null) { - if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { + // foreach (Synapse synapse in layerNeuroid.synapses.Values) { + // if (synapse.neuroid != null) { + // if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { - Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + // Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; + foreach ((Nucleus neuroid, Synapse synapse) in layerNeuroid.synapses) { + if (neuroid != null) { + if (this.neuroidPositions.ContainsKey(neuroid)) { + Vector2Int inputNeuroidPos = this.neuroidPositions[neuroid]; if (inputNeuroidPos.x == layerNeuroidPos.x + 1) { Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); diff --git a/Assets/NanoBrain/NanoBrain.cs b/Assets/NanoBrain/NanoBrain.cs new file mode 100644 index 0000000..43a9e33 --- /dev/null +++ b/Assets/NanoBrain/NanoBrain.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using UnityEngine; + +public class NanoBrain : MonoBehaviour { + public List neuroids = new(); + + public Neuroid AddNeuron(string name) { + Neuroid neuroid = new(this, name); + return neuroid; + } + + public void Update() { + foreach (Neuroid neuroid in neuroids) { + neuroid.stale++; + if (neuroid.IsStale()) + neuroid.outputValue = Vector3.zero; + } + } +} diff --git a/Assets/NanoBrain/NanoBrain.cs.meta b/Assets/NanoBrain/NanoBrain.cs.meta new file mode 100644 index 0000000..078dc8f --- /dev/null +++ b/Assets/NanoBrain/NanoBrain.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 74e1478743ac3bc078cbe8501c287e98 \ No newline at end of file diff --git a/Assets/NanoBrain/Neuroid.cs b/Assets/NanoBrain/Neuroid.cs index f4ff48b..3589f4d 100644 --- a/Assets/NanoBrain/Neuroid.cs +++ b/Assets/NanoBrain/Neuroid.cs @@ -3,32 +3,30 @@ using UnityEngine; using System.Linq; public class Synapse { - public Synapse(Nucleus neuroid, Vector3 value, float weight) { - this.neuroid = neuroid; - this.value = value; + public Synapse(Nucleus neuroid, float weight = 1.0f) { + //this.neuroid = neuroid; this.weight = weight; } - public Nucleus neuroid; - public Vector3 value; + //public Nucleus neuroid; public float weight; } -public class NeuroidNetwork { - public List neuroids = new(); +// public class NeuroidNetwork { +// public List neuroids = new(); - public Neuroid AddNeuron(string name) { - Neuroid neuroid = new(this, name); - return neuroid; - } +// public Neuroid AddNeuron(string name) { +// Neuroid neuroid = new(this, name); +// return neuroid; +// } - public void Update() { - foreach (Neuroid neuroid in neuroids) { - neuroid.stale++; - if (neuroid.IsStale()) - neuroid.outputValue = Vector3.zero; - } - } -} +// public void Update() { +// foreach (Neuroid neuroid in neuroids) { +// neuroid.stale++; +// if (neuroid.IsStale()) +// neuroid.outputValue = Vector3.zero; +// } +// } +// } public class Neuroid : Nucleus { public int stale = 0; @@ -40,19 +38,21 @@ public class Neuroid : Nucleus { public bool inverse = false; public float exponent = 1.0f; - public NeuroidNetwork net; + //public NeuroidNetwork net; + public NanoBrain net; - public Neuroid(NeuroidNetwork net, string name) : base(name) { + // public Neuroid(NeuroidNetwork net, string name) : base(name) { + public Neuroid(NanoBrain net, string name) : base(name) { this.net = net; if (this.net != null) this.net.neuroids.Add(this); - else + else Debug.LogError("No neuroid network"); } public void AddSynapse(Neuroid input) { input.AddReceiver(this); - this.synapses[input] = new(input, Vector3.zero, 1.0f); + this.synapses[input] = new(input); } // public void AddReceiver(Neuroid receiver) { @@ -69,33 +69,28 @@ public class Neuroid : Nucleus { this.synapses[input].weight = weight; } else { - this.synapses[input] = new(input, Vector3.zero, weight); + this.synapses[input] = new(input, weight); } } public void GetInputFrom(Neuroid input, float weight = 1.0f) { input.AddReceiver(this); - this.synapses[input] = new(input, Vector3.zero, weight); + this.synapses[input] = new(input, weight); } - public void SetInput(Neuroid input, Vector3 value) { - if (this.synapses.ContainsKey(input)) { - Synapse synapse = this.synapses[input]; - synapse.value = value; - } - else - this.synapses[input] = new(null, value, 1.0f); + public void SetInput(Neuroid input) { + if (this.synapses.ContainsKey(input) == false) + this.synapses[input] = new(input); UpdateState(); } - public void SetInput(Neuroid input, Vector3 value, float weight) { + public void SetInput(Neuroid input, float weight) { if (this.synapses.ContainsKey(input)) { Synapse synapse = this.synapses[input]; - synapse.value = value; synapse.weight = weight; } else - this.synapses[input] = new(null, value, weight); + this.synapses[input] = new(input, weight); UpdateState(); } @@ -105,38 +100,28 @@ public class Neuroid : Nucleus { // In case this was the last synapse, we reset the output because in this case no updates from synapses will follow. this.outputValue = Vector3.zero; foreach (Neuroid neuroid in this.outputNeuroids) - neuroid.SetInput(this, this.outputValue); + neuroid.SetInput(this); } } - // public readonly Dictionary fakeNeuroids = new(); - // public void SetInput(int thingId, Vector3 value, float weight, NeuroidNetwork net) { - // if (fakeNeuroids.ContainsKey(thingId)) { - // Neuroid fakeInput = fakeNeuroids[thingId]; - // Synapse synapse = this.synapses[fakeInput]; - // synapse.value = value; - // synapse.weight = weight; - // } - // else { - // fakeNeuroids[thingId] = new(net); - // this.synapses[fakeNeuroids[thingId]] = new(null, value, weight); - // } - // UpdateState(); - // } - - protected virtual void UpdateState() { + public virtual void UpdateState() { Vector3 result = Vector3.zero; - foreach (Synapse synapse in this.synapses.Values) { - // if (synapse.neuroid == null) - // continue; - Vector3 direction = synapse.value.normalized; - float magnitude = synapse.value.magnitude; + foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { + // foreach (Synapse synapse in this.synapses.Values) { + // if (synapse.neuroid == null) + // Debug.LogWarning(" disconnected synapse"); + // if (synapse.value != synapse.neuroid.outputValue) + // Debug.LogWarning("synapse value error"); + // Vector3 direction = synapse.value.normalized; + // float magnitude = synapse.value.magnitude; // Vector3 direction = synapse.neuroid.outputValue.normalized; // float magnitude = synapse.neuroid.outputValue.magnitude; + Vector3 direction = nucleus.outputValue.normalized; + float magnitude = nucleus.outputValue.magnitude; magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); - if (inverse) + if (inverse && magnitude > 0) magnitude = 1 / magnitude; result += direction * magnitude; } @@ -145,7 +130,7 @@ public class Neuroid : Nucleus { this.outputValue = result; foreach (Neuroid neuroid in this.outputNeuroids) - neuroid.SetInput(this, this.outputValue); + neuroid.SetInput(this); this.stale = 0; } diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index 6fac46d..b8e4a15 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -16,6 +16,6 @@ public class Nucleus { public virtual void AddReceiver(Neuroid receiver) { this.outputNeuroids.Add(receiver); - receiver.synapses[this] = new(this, Vector3.zero, 1.0f); + receiver.synapses[this] = new(this); } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index c38f12b..bd9cfe4 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -5,7 +5,8 @@ using UnityEngine; public class Perception : Nucleus { public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; - public NeuroidNetwork neuroidNet { get; protected set; } + // public NeuroidNetwork neuroidNet { get; protected set; } + public NanoBrain neuroidNet { get; protected set; } public class Receiver { public int thingType = 0; @@ -15,7 +16,8 @@ public class Perception : Nucleus { public HashSet positionReceivers { get; protected set; } public HashSet velocityReceivers { get; protected set; } - public Perception(NeuroidNetwork neuroidNet) : base("Perception") { + // public Perception(NeuroidNetwork neuroidNet) : base("Perception") { + public Perception(NanoBrain neuroidNet) : base("Perception") { this.neuroidNet = neuroidNet; this.positionReceivers = new(); this.velocityReceivers = new(); @@ -30,7 +32,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null) { neuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = new(neuroid, Vector3.zero, weight); + receivingNeuroid.synapses[neuroid] = new(neuroid, weight); } } } @@ -43,7 +45,7 @@ public class Perception : Nucleus { foreach (SensoryNeuroid neuroid in sensoryNeuroids) { if (neuroid != null && neuroid.velocityNeuroid != null) { neuroid.velocityNeuroid.AddReceiver(receivingNeuroid); - receivingNeuroid.synapses[neuroid] = new(neuroid, Vector3.zero, 1.0f); + receivingNeuroid.synapses[neuroid] = new(neuroid); } } } diff --git a/Assets/NanoBrain/SensoryNeuroid.cs b/Assets/NanoBrain/SensoryNeuroid.cs index 50558ec..a55fa02 100644 --- a/Assets/NanoBrain/SensoryNeuroid.cs +++ b/Assets/NanoBrain/SensoryNeuroid.cs @@ -1,13 +1,36 @@ +using System.Collections.Generic; using System.Linq; using UnityEngine; +public class Receptor { + + public SensoryNeuroid neuroid; + + public int thingId; + public Vector3 value; + + /// + /// Local position of the thing + /// + public virtual Vector3 position { + get { + return this.value; + } + set { + this.value = value; + neuroid.UpdateState(); + } + } +} + public class SensoryNeuroid : Neuroid { // A neuroid which has no neurons as input // But receives value from a receptor public Receptor receptor; public VelocityNeuroid velocityNeuroid; - public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") { + // public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") { + public SensoryNeuroid(NanoBrain net, int thingId) : base(net, "sensory neuroid") { this.receptor = new Receptor { neuroid = this, thingId = thingId @@ -17,27 +40,34 @@ public class SensoryNeuroid : Neuroid { this.AddReceiver(velocityNeuroid); } -} + public override void UpdateState() { + Vector3 result = receptor.value; + // SensoryNeuroid normally do not have synapses... + // foreach (Synapse synapse in this.synapses.Values) { + // if (synapse.neuroid == null) + // Debug.LogWarning(" disconnected synapse"); + // // if (synapse.value != synapse.neuroid.outputValue) + // // Debug.LogWarning("synapse value error"); + // // Vector3 direction = synapse.value.normalized; + // // float magnitude = synapse.value.magnitude; -public class Receptor { - - public SensoryNeuroid neuroid; - - public int thingId; - /// - /// Local position of the thing - /// - public virtual Vector3 position { - get { - if (neuroid != null) - return neuroid.synapses[neuroid].value; - else - return Vector3.zero; - } - set { - if (neuroid != null) - neuroid.SetInput(neuroid, value); + // Vector3 direction = synapse.neuroid.outputValue.normalized; + // float magnitude = synapse.neuroid.outputValue.magnitude; + foreach ((Nucleus nucleus, Synapse synapse) in this.synapses) { + Vector3 direction = nucleus.outputValue.normalized; + float magnitude = nucleus.outputValue.magnitude; + magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); + if (inverse) + magnitude = 1 / magnitude; + result += direction * magnitude; } + if (average && this.synapses.Count > 0) + result /= this.synapses.Count + 1; + + this.outputValue = result; + foreach (Neuroid neuroid in this.outputNeuroids) + neuroid.SetInput(this); + this.stale = 0; } } @@ -46,12 +76,14 @@ public class VelocityNeuroid : Neuroid { private Vector3 lastPosition = Vector3.zero; private float lastValueTime = 0; - public VelocityNeuroid(NeuroidNetwork net) : base(net, "Velocity") { + // public VelocityNeuroid(NeuroidNetwork net) : base(net, "Velocity") { + public VelocityNeuroid(NanoBrain net) : base(net, "Velocity") { } - protected override void UpdateState() { + public override void UpdateState() { // Assuming only one synapse for now.... - Vector3 currentPosition = this.synapses.First().Value.value; + //Vector3 currentPosition = this.synapses.First().Value.neuroid.outputValue; + Vector3 currentPosition = this.synapses.First().Key.outputValue; float currentValueTime = Time.time; float deltaTime = currentValueTime - lastValueTime; @@ -61,7 +93,7 @@ public class VelocityNeuroid : Neuroid { // No activation function... this.outputValue = velocity; foreach (Neuroid receiver in outputNeuroids) - receiver?.SetInput(this, this.outputValue); + receiver?.SetInput(this); this.stale = 0; this.lastValueTime = Time.time; diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index ce4720b..9827fcf 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -371,7 +371,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0464906885ae3494f8fd0314719fb2db, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmControl - speed: 1 + speed: 2 inertia: 0.1 alignmentForce: 5 cohesionForce: 5 diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index 9a2f7c8..4b66dd9 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -1,16 +1,7 @@ using UnityEngine; - +[RequireComponent(typeof(NanoBrain))] public class Boid : MonoBehaviour { - // public float speed = 0.2f; - // public int neighbourCount = 0; - // public float inertia = 0.2f; - // public float alignmentForce = 1.0f; - // public float cohesionForce = 1.0f; - // public float separationForce = 1.0f; - // public float separationDistance = 0.5f; - // public float bodyForce = 1; - public const int BoundaryType = 1; public const int BoidType = 2; @@ -21,7 +12,8 @@ public class Boid : MonoBehaviour { private Bounds innerBounds; private Bounds outerBounds; - public NeuroidNetwork neuroidNet = new(); + //public NeuroidNetwork neuroidNet = new(); + public NanoBrain neuroidNet; public Perception perception; public Nucleus behaviour; @@ -31,6 +23,8 @@ public class Boid : MonoBehaviour { public int id; void Awake() { + neuroidNet = GetComponent(); + this.id = this.GetInstanceID(); sc = FindFirstObjectByType(); @@ -48,7 +42,7 @@ public class Boid : MonoBehaviour { } void Update() { - Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); + Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance); foreach (Collider c in results) { if (c as CapsuleCollider != null) { Boid neighbour = c.GetComponentInParent(); @@ -103,7 +97,9 @@ public class Boid : MonoBehaviour { } void OnDrawGizmosSelected() { - Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); + if (sc == null) + return; + Gizmos.DrawWireSphere(this.transform.position, sc.perceptionDistance); Gizmos.color = Color.yellow; Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); Gizmos.DrawRay(transform.position, worldForce * 10); diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs index 50b6912..ac510bf 100644 --- a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -3,7 +3,8 @@ public class Roaming : Nucleus { public Neuroid output; - public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { + // public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { + public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") { avoidance = new(neuroidNet, "Avoidance") { inverse = true }; perception.SendPositions(avoidance, 1.0f, 1); diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs index f416c38..23831bf 100644 --- a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -12,7 +12,8 @@ public class Swarming : Nucleus { public const int BoundaryType = 1; public const int BoidType = 2; - public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { + // public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { + public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") { this.cohesion = new(neuroidNet, "Cohesion"); perception.SendPositions(this.cohesion, 1.0f, BoidType); @@ -23,7 +24,7 @@ public class Swarming : Nucleus { perception.SendPositions(this.avoidance); this.output = new(neuroidNet, "Swarming"); - //this.output.GetInputFrom(alignment, sc.alignmentForce); + this.output.GetInputFrom(alignment, sc.alignmentForce); this.output.GetInputFrom(cohesion, sc.cohesionForce); this.output.GetInputFrom(avoidance, -sc.avoidanceForce); }