This commit is contained in:
Pascal Serrarens 2025-12-05 16:41:11 +01:00
parent 605bdfc629
commit 86b5053383
15 changed files with 203 additions and 70 deletions

View File

@ -5,18 +5,18 @@ public class NanoBrain : MonoBehaviour {
// public NucleusObj rootNucleus;
public List<Neuroid> neuroids = new();
// public List<Neuroid> 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 UpdateNeurons() {
foreach (Neuroid neuroid in neuroids) {
neuroid.stale++;
if (neuroid.isSleeping)
neuroid.outputValue = Vector3.zero;
}
}
// public void UpdateNeurons() {
// foreach (Neuroid neuroid in neuroids) {
// neuroid.stale++;
// if (neuroid.isSleeping)
// neuroid.outputValue = Vector3.zero;
// }
// }
}

View File

@ -5,13 +5,13 @@ public class Neuroid : Nucleus {
public bool inverse = false;
public float exponent = 1.0f;
public Neuroid(NanoBrain brain, string name) : base(null, name) {
this.brain = brain;
if (this.brain != null)
this.brain.neuroids.Add(this);
else
Debug.LogError("No neuroid network");
}
// public Neuroid(NanoBrain brain, string name) : base(null, name) {
// this.brain = brain;
// if (this.brain != null)
// this.brain.neuroids.Add(this);
// else
// Debug.LogError("No neuroid network");
// }
public Neuroid(NanoBrainObj brain, string name) : base(brain, name) {
}

View File

@ -38,7 +38,7 @@ public class Nucleus {
#region Runtime state (not serialized)
public NanoBrain brain { get; protected set; }
// public NanoBrain brain { get; protected set; }
public NanoBrainObj newBrain { get; protected set; }
public virtual Vector3 outputValue { get; set; }
@ -80,7 +80,7 @@ public class Nucleus {
}
foreach (Receiver receiver in nucleus.receivers)
receiver.nucleus.synapses.RemoveAll(s => s.nucleus == nucleus);
nucleus.newBrain.nuclei.RemoveAll(n => n == nucleus);
}

View File

@ -1,31 +1,27 @@
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Perception : Nucleus {
public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7];
[System.Serializable]
public class Receiver {
public int thingType = 0;
public Nucleus neuroid;
}
public HashSet<Receiver> positionReceivers { get; protected set; }
public HashSet<Receiver> velocityReceivers { get; protected set; }
//public HashSet<Receiver> positionReceivers { get; protected set; }
public List<Receiver> positionReceivers;
//public HashSet<Receiver> velocityReceivers { get; protected set; }
public List<Receiver> velocityReceivers;
public Perception(NanoBrainObj brain) : base(brain, "Perception") {
//this.brain = brain;
this.positionReceivers = new();
this.velocityReceivers = new();
}
public Perception(NanoBrain neuroidNet) : base(null, "Perception") {
this.brain = neuroidNet;
this.positionReceivers = new();
this.velocityReceivers = new();
}
public void SendPositions(Nucleus receivingNeuroid, int thingType = 0, float weight = 1.0f) {
Receiver receiver = new() {
thingType = thingType,
@ -78,18 +74,20 @@ public class Perception : Nucleus {
if (availableIx != -1) {
SensoryNeuroid neuroid;
if (sensoryNeuroids[availableIx] != null) {
// Debug.Log($"replace receptor for {thingId} at {availableIx}");
Debug.Log($"replace receptor for {thingId} at {availableIx}");
neuroid = sensoryNeuroids[availableIx];
neuroid.Replace(thingId, name);
}
else {
// Debug.Log($"new receptor for {thingId} at {availableIx}");
neuroid = new(brain, thingId, name);
Debug.Log($"new receptor for {thingId} at {availableIx}");
neuroid = new(newBrain, thingId, name);
sensoryNeuroids[availableIx] = neuroid;
}
foreach (Receiver receiver in positionReceivers) {
if (receiver.thingType == 0 || receiver.thingType == thingType)
if (receiver.thingType == 0 || receiver.thingType == thingType) {
Debug.Log("Add position receiver");
receiver.neuroid.GetInputFrom(neuroid);
}
}
foreach (Receiver receiver in velocityReceivers) {
if (receiver.thingType == 0 || receiver.thingType == thingType)

View File

@ -29,14 +29,13 @@ public class SensoryNeuroid : Neuroid {
public Receptor receptor;
public VelocityNeuroid velocityNeuroid;
// public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") {
public SensoryNeuroid(NanoBrain net, int thingId, string name = "sensor") : base(net, name) {
public SensoryNeuroid(NanoBrainObj brain, int thingId, string name = "sensor") : base(brain, name) {
this.name = name + ": position";
this.receptor = new Receptor {
neuroid = this,
thingId = thingId
};
this.velocityNeuroid = new(net, name + ": velocity");
this.velocityNeuroid = new(brain, name + ": velocity");
// The velocity neuroid received position data from this
this.AddReceiver(velocityNeuroid);
}
@ -87,7 +86,7 @@ public class VelocityNeuroid : Neuroid {
private Vector3 lastPosition = Vector3.zero;
private float lastValueTime = 0;
public VelocityNeuroid(NanoBrain net, string name = "velocity") : base(net, name) {
public VelocityNeuroid(NanoBrainObj net, string name = "velocity") : base(net, name) {
}
public void Replace(string name = "velocity") {

View File

@ -10,10 +10,6 @@ public class NanoBrainInspector : Editor {
protected static VisualElement mainContainer;
protected static VisualElement inspectorContainer;
//private Nucleus currentNucleus = null;
private List<NeuroidLayer> layers = new();
private Dictionary<Nucleus, Vector2Int> neuroidPositions = new();
protected bool breakOnWake = false;
#region Start
@ -241,22 +237,20 @@ public class NanoBrainInspector : Editor {
Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus];
Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f);
//int i = 0;
float inputSpacing = 400f / layerNucleus.synapses.Count;
float inputMargin = 10 + inputSpacing / 2;
int minStale = 10000;
//foreach ((Nucleus nucleus, float weight) in layerNucleus.synapses) {
Debug.Log($"layer neuron {layerNucleus.name} has {layerNucleus.synapses.Count} synapses");
foreach (Synapse synapse in layerNucleus.synapses) {
Nucleus nucleus = synapse.nucleus;
if (nucleus != null) {
float weight = synapse.weight;
Debug.Log($"Synapse to {nucleus.name} is valid"); float weight = synapse.weight;
if (this.neuroidPositions.ContainsKey(nucleus)) {
Vector2Int inputNeuroidPos = this.neuroidPositions[nucleus];
if (inputNeuroidPos.x == layerNeuroidPos.x + 1) {
Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f);
//float brightness = weight / 10.0f;
Handles.color = Color.white; //new Color(brightness, brightness, brightness);
Handles.color = Color.white;
Handles.DrawLine(parentPos, pos);
}
}
@ -265,11 +259,12 @@ public class NanoBrainInspector : Editor {
}
}
// if (layerNucleus.synapses.Count > 0 && minStale > 2 && layerNucleus.stale < 3)
// Debug.LogWarning($"Strange {minStale} is big duing update");
float size = 20;
if (layerNucleus == this.currentNucleus) {
Handles.color = Color.white;
Handles.DrawSolidDisc(parentPos, Vector3.forward, size + 2);
}
if (layerNucleus.isSleeping)
Handles.color = Color.darkRed;
else {
@ -293,7 +288,6 @@ public class NanoBrainInspector : Editor {
// Process Hover
HandleMouseHover(layerNucleus, neuronRect);
// Process click
// Debug.Log($"{et} {e.type}");
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();

View File

@ -29,10 +29,10 @@ public class NanoBrainObj : ScriptableObject, ISerializationCallbackReceiver {
}
public void UpdateNuclei() {
foreach (Neuroid neuroid in nuclei) {
neuroid.stale++;
if (neuroid.isSleeping)
neuroid.outputValue = Vector3.zero;
foreach (Nucleus nucleus in nuclei) {
nucleus.stale++;
if (nucleus.isSleeping)
nucleus.outputValue = Vector3.zero;
}
}

View File

@ -393,7 +393,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn
count: 20
count: 1
boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3}
spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5}
minDelay: 0.05

View File

@ -13,16 +13,48 @@ MonoBehaviour:
m_Name: New Nano Brain Obj
m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj
title:
count: 0
count: -26
color: {r: 1, g: 1, b: 1, a: 1}
texture: {fileID: 0}
nuclei:
- id: 257807948
_name: Root
synapses: []
synapses:
- nucleusId: -651011940
weight: 1
- nucleusId: -1689048724
weight: 1
receivers: []
- id: -1868865374
_name: Perception
synapses: []
receivers: []
- id: -651011940
_name: Neuron 1
synapses: []
receivers:
- nucleusId: 257807948
- id: -1689048724
_name: New neuron
synapses: []
receivers:
- nucleusId: 257807948
- id: -152927560
_name: 'Boundary: position'
synapses: []
receivers:
- nucleusId: -1462684836
- id: -1462684836
_name: 'Boundary: velocity'
synapses:
- nucleusId: -152927560
weight: 1
receivers: []
rootId: 257807948
perception:
id: 1565766940
_name: Perception
synapses: []
receivers: []
positionReceivers: []
velocityReceivers: []

View File

@ -176,4 +176,4 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 92f34a5e4027a1dc39efd8ce63cf6aba, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NanoBrainComponent
brain: {fileID: 11400000, guid: 55099766f6f09071ab4e8c89b02fa302, type: 2}
brain: {fileID: 11400000, guid: af8d90b8b4b9dcad7837130c4143d91c, type: 2}

View File

@ -0,0 +1,102 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 36081359186edfec998d891a1feeb17b, type: 3}
m_Name: RoamingBrain
m_EditorClassIdentifier: Assembly-CSharp::NanoBrainObj
title:
count: 0
color: {r: 1, g: 1, b: 1, a: 1}
texture: {fileID: 0}
nuclei:
- id: -1753291412
_name: Root
synapses:
- nucleusId: 237822944
weight: 1
receivers: []
- id: 472852910
_name: Perception
synapses: []
receivers: []
- id: 237822944
_name: Avoidance
synapses: []
receivers:
- nucleusId: -1753291412
- id: 983561152
_name: 'Boundary: position'
synapses: []
receivers:
- nucleusId: -1818801134
- id: -1818801134
_name: 'Boundary: velocity'
synapses:
- nucleusId: 983561152
weight: 1
receivers: []
- id: 1386590800
_name: 'Boundary: position'
synapses: []
receivers:
- nucleusId: -1415771486
- nucleusId: 237822944
- id: -1415771486
_name: 'Boundary: velocity'
synapses:
- nucleusId: 1386590800
weight: 1
receivers: []
- id: -213085248
_name: 'Boundary: position'
synapses: []
receivers:
- nucleusId: 1279519762
- nucleusId: 237822944
- id: 1279519762
_name: 'Boundary: velocity'
synapses:
- nucleusId: -213085248
weight: 1
receivers: []
- id: 1783940116
_name: 'Boundary: position'
synapses: []
receivers:
- nucleusId: -1018422170
- nucleusId: 237822944
- id: -1018422170
_name: 'Boundary: velocity'
synapses:
- nucleusId: 1783940116
weight: 1
receivers: []
rootId: -1753291412
perception:
id: 2139386530
_name: Perception
synapses: []
receivers: []
positionReceivers:
- thingType: 0
neuroid:
id: 237822944
_name: Avoidance
synapses:
- nucleusId: 1386590800
weight: 1
- nucleusId: -213085248
weight: 1
- nucleusId: 1783940116
weight: 1
receivers:
- nucleusId: -1753291412
velocityReceivers: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: af8d90b8b4b9dcad7837130c4143d91c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -24,7 +24,7 @@ public class Boid : MonoBehaviour {
public int id;
void Awake() {
nanoBrain = GetComponent<NanoBrainComponent>();
this.id = this.GetInstanceID();
sc = FindFirstObjectByType<SwarmControl>();

View File

@ -3,11 +3,11 @@ public class Roaming : Nucleus {
public Neuroid output;
public Roaming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base(null, "Roaming nucleus") {
avoidance = new(neuroidNet, "Avoidance") { inverse = true };
public Roaming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Roaming nucleus") {
avoidance = new(brain, "Avoidance") { inverse = true };
perception.SendPositions(avoidance, Boid.BoundaryType);
this.output = new(neuroidNet, "Roaming");
this.output = new(brain, "Roaming");
output.GetInputFrom(avoidance, -sc.avoidanceForce);
}

View File

@ -10,20 +10,20 @@ public class Swarming : Nucleus {
public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; }
public Swarming(NanoBrain neuroidNet, Perception perception, SwarmControl sc) : base(null, "Swarming Nucleus") {
this.cohesion = new(neuroidNet, "Cohesion") { inverse = false };
public Swarming(NanoBrainObj brain, Perception perception, SwarmControl sc) : base(null, "Swarming Nucleus") {
this.cohesion = new(brain, "Cohesion") { inverse = false };
perception.SendPositions(this.cohesion, Boid.BoidType);
this.alignment = new(neuroidNet, "Alignment") { average = true };
this.alignment = new(brain, "Alignment") { average = true };
perception.SendVelocities(this.alignment, Boid.BoidType);
this.avoidance = new(neuroidNet, "Avoidance") { inverse = true };
this.avoidance = new(brain, "Avoidance") { inverse = true };
perception.SendPositions(this.avoidance);
this.boundary = new(neuroidNet, "Boundary");
this.boundary = new(brain, "Boundary");
perception.SendPositions(this.boundary, Boid.BoundaryType);
this.output = new(neuroidNet, "Swarming");
this.output = new(brain, "Swarming");
this.output.GetInputFrom(alignment, sc.alignmentForce);
this.output.GetInputFrom(cohesion, sc.cohesionForce);
this.output.GetInputFrom(avoidance, -sc.avoidanceForce);