improved sensoryneuroids

This commit is contained in:
Pascal Serrarens 2025-11-26 17:40:06 +01:00
parent cb04a7645b
commit 2e803179e3
5 changed files with 56 additions and 56 deletions

View File

@ -38,15 +38,18 @@ public class GraphEditorWindow : EditorWindow {
foreach (Neuroid neuroid in neuroids) { foreach (Neuroid neuroid in neuroids) {
// If this neuroid is not visited while its output neuroid is visited // 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 // Add it to the next layer
currentLayer.neuroids.Add(neuroid); currentLayer.neuroids.Add(neuroid);
neuroid.layerIx = layerIx;
// Register it as visited // Register it as visited
neuronVisited.Add(neuroid); neuronVisited.Add(neuroid);
// Store its position // Store its position
Vector2Int neuroidPosition = new(layerIx, neuroidIx); Vector2Int neuroidPosition = new(layerIx, neuroidIx);
neuroidPositions[neuroid] = neuroidPosition; neuroidPositions[neuroid] = neuroidPosition;
neuroidIx++; 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) foreach (NeuroidLayer layer in layers)
DrawLayer(layer); 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) { private void DrawLayer(NeuroidLayer layer) {
int column = layer.ix * 100; int column = layer.ix * 100;
int nodeCount = layer.neuroids.Count; int nodeCount = layer.neuroids.Count;
@ -151,7 +121,7 @@ public class GraphEditorWindow : EditorWindow {
float size = layerNeuroid.outputValue.magnitude / maxValue * 20; float size = layerNeuroid.outputValue.magnitude / maxValue * 20;
Handles.color = Color.white; Handles.color = Color.white;
Handles.DrawSolidDisc(parentPos, Vector3.forward, size); 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)) if (neuronRect.Contains(Event.current.mousePosition))
HandleMouseHover(layerNeuroid, neuronRect); HandleMouseHover(layerNeuroid, neuronRect);
i++; i++;

View File

@ -26,6 +26,8 @@ public class Neuroid {
public int id; public int id;
public string name; public string name;
public int layerIx;
public readonly Dictionary<int, Synapse> synapses = new(); public readonly Dictionary<int, Synapse> synapses = new();
public Vector3 outputValue; public Vector3 outputValue;

View File

@ -1,6 +1,6 @@
using UnityEngine; using UnityEngine;
class Receptor { public class Receptor {
public SensoryNeuroid neuroid; public SensoryNeuroid neuroid;
public void SetValue(Vector3 value) { public void SetValue(Vector3 value) {
if (neuroid != null) { if (neuroid != null) {
@ -10,10 +10,15 @@ class Receptor {
} }
class SensoryNeuroid : Neuroid { public class SensoryNeuroid : Neuroid {
public Receptor receptor; 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
};
} }
} }

View File

@ -1,8 +1,7 @@
using UnityEngine; using UnityEngine;
public class Boid : MonoBehaviour public class Boid : MonoBehaviour {
{
public float speed = 0.2f; public float speed = 0.2f;
public int neighbourCount = 0; public int neighbourCount = 0;
public float inertia = 0.2f; public float inertia = 0.2f;
@ -20,6 +19,8 @@ public class Boid : MonoBehaviour
readonly Collider[] results = new Collider[10]; readonly Collider[] results = new Collider[10];
public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6];
public NeuroidNetwork neuroidNet = new(); public NeuroidNetwork neuroidNet = new();
public Neuroid bodyVector; public Neuroid bodyVector;
public Neuroid cohesion; public Neuroid cohesion;
@ -32,15 +33,17 @@ public class Boid : MonoBehaviour
public int id; public int id;
void Awake() void Awake() {
{
this.id = this.GetInstanceID(); this.id = this.GetInstanceID();
sc = FindFirstObjectByType<SwarmControl>(); sc = FindFirstObjectByType<SwarmControl>();
bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); 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 = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum };
//cohesion.GetInputFrom(neighbourSensor);
alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average };
separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum }; separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum };
target = new(neuroidNet) { name = "Target", 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); totalForce.GetInputFrom(boundary, sc.boundaryForce);
} }
void Update() void Update() {
{
Physics.OverlapSphereNonAlloc(this.transform.position, 10, results); Physics.OverlapSphereNonAlloc(this.transform.position, 10, results);
neighbourCount = 0; neighbourCount = 0;
@ -64,13 +66,11 @@ public class Boid : MonoBehaviour
alignment.ResetWeights(); alignment.ResetWeights();
separation.ResetWeights(); separation.ResetWeights();
foreach (Collider c in results) foreach (Collider c in results) {
{
if (c == null) if (c == null)
continue; continue;
if (c as CapsuleCollider != null) if (c as CapsuleCollider != null) {
{
Boid neighbour = c.GetComponentInParent<Boid>(); Boid neighbour = c.GetComponentInParent<Boid>();
if (neighbour == null || neighbour == this) if (neighbour == null || neighbour == this)
continue; continue;
@ -79,12 +79,15 @@ public class Boid : MonoBehaviour
Vector3 relativeVelocity = neighbour.velocity - this.velocity; Vector3 relativeVelocity = neighbour.velocity - this.velocity;
int id = neighbour.GetInstanceID(); int id = neighbour.GetInstanceID();
Receptor receptor = GetReceptor(id);
if (receptor != null) {
receptor.SetValue(localPosition);
}
Vector3 separationForce = -localPosition / localPosition.sqrMagnitude; Vector3 separationForce = -localPosition / localPosition.sqrMagnitude;
// which is equivalent to -(localPosition.normalized / localPosition.magnitude) // which is equivalent to -(localPosition.normalized / localPosition.magnitude)
separation.SetInput(id, separationForce, sc.separationDistance); separation.SetInput(id, separationForce, sc.separationDistance);
cohesion.SetInput(id, localPosition, sc.cohesionForce); //cohesion.SetInput(id, localPosition, sc.cohesionForce);
alignment.SetInput(id, relativeVelocity, sc.alignmentForce); alignment.SetInput(id, relativeVelocity, sc.alignmentForce);
neighbourCount++; neighbourCount++;
@ -92,8 +95,7 @@ public class Boid : MonoBehaviour
} }
//Vector3 spaceLocalPosition = sc.transform.InverseTransformPoint(this.transform.position); //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 point = this.transform.position;
// Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max); // Vector3 distanceOutside = Vector3.Max(bounds.min - this.transform.position, this.transform.position - bounds.max);
// // Ensure value is > 0 (but isn't this already) // // Ensure value is > 0 (but isn't this already)
@ -109,7 +111,7 @@ public class Boid : MonoBehaviour
outside = direction * magnitude; outside = direction * magnitude;
boundary.SetInput(id, outside, sc.boundaryForce); 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; Vector3 totalForceVector = totalForce.outputValue;
@ -120,11 +122,28 @@ public class Boid : MonoBehaviour
this.transform.position += this.velocity * Time.deltaTime; this.transform.position += this.velocity * Time.deltaTime;
if (this.velocity != Vector3.zero) if (this.velocity != Vector3.zero) {
{
Quaternion targetRotation = Quaternion.LookRotation(this.velocity); Quaternion targetRotation = Quaternion.LookRotation(this.velocity);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation 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;
}
} }

4
NanoBrain-Unity.slnx Normal file
View File

@ -0,0 +1,4 @@
<Solution>
<Project Path="Assembly-CSharp.csproj" />
<Project Path="Assembly-CSharp-Editor.csproj" />
</Solution>