Perceptoid pool starts to work

This commit is contained in:
Pascal Serrarens 2025-12-11 16:50:03 +01:00
parent dc8ac7ef9b
commit 4e8d10f1bd
7 changed files with 136 additions and 144 deletions

View File

@ -11,12 +11,16 @@ public class Perceptoid : Neuroid {
[SerializeField]
public int thingType;
public int thingId;
public override void Rebuild(NanoBrainObj brain) {
base.Rebuild(brain);
this.receptor = new Receptor() {
neuroid = this
};
//this.receptor = new Receptor(this);
this.receptor = Perceptoid.GetReceptor(brain, thingType);
if (this.receptor == null)
this.receptor = new Receptor(this);
else
this.receptor.perceptei.Add(this);
}
public override void Deserialize(Nucleus nucleus) {
@ -57,9 +61,7 @@ public class Perceptoid : Neuroid {
this.nucleusType = nameof(Perceptoid);
this.name = name;
this.receptor = new Receptor {
neuroid = this
};
this.receptor = new Receptor(this);
}
public Perceptoid(NanoBrainObj brain, int thingType, string name = "sensor") : base(name) {
@ -73,8 +75,7 @@ public class Perceptoid : Neuroid {
this.nucleusType = nameof(Perceptoid);
this.name = name;
this.thingType = thingType;
this.receptor = new Receptor {
neuroid = this,
this.receptor = new Receptor(this) {
thingType = thingType
};
this.velocityNeuroid = new(brain, name + ": velocity");
@ -119,6 +120,31 @@ public class Perceptoid : Neuroid {
this.stale = 0;
}
public void UpdateState(int thingId, Vector3 receptorValue) {
this.thingId = thingId;
Vector3 result = receptorValue;
foreach (Synapse synapse in this.synapses) {
Nucleus nucleus = synapse.nucleus;
float weight = synapse.weight;
Vector3 direction = nucleus.outputValue.normalized;
float magnitude = nucleus.outputValue.magnitude;
magnitude = 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 (Receiver receiver in this.receivers)
if (receiver.nucleus is Neuroid neuroid)
neuroid.SetInput(this);
this.stale = 0;
}
public static Perceptoid GetPerception(NanoBrainObj brain, int thingType = 0) {
foreach (Nucleus nucleus in brain.nuclei) {
if (nucleus is Perceptoid perceptoid && (thingType == 0 || perceptoid.thingType == thingType))

View File

@ -4,13 +4,18 @@ using UnityEngine;
public class Receptor {
public Neuroid neuroid;
public List<Perceptoid> perceptoids;
private Neuroid neuroid;
public List<Perceptoid> perceptei = new();
public int thingId;
public int thingType;
public Vector3 localPosition;
public Receptor(Perceptoid perceptoid) {
this.neuroid = perceptoid;
this.perceptei.Add(perceptoid);
}
/// <summary>
/// Local position of the thing
/// </summary>
@ -27,7 +32,29 @@ public class Receptor {
public virtual void ProcessStimulus(int thingId, Vector3 localPosition) {
this.thingId = thingId;
this.localPosition = localPosition;
neuroid.UpdateState();
//perceptoids[0].UpdateState();
///neuroid.UpdateState();
Perceptoid selectedPerceptoid = null;
foreach (Perceptoid perceptoid in this.perceptei) {
if (perceptoid.thingId == this.thingId) {
selectedPerceptoid = perceptoid;
break;
}
else if (perceptoid.isSleeping)
selectedPerceptoid = perceptoid;
else if (selectedPerceptoid == null) {
selectedPerceptoid = perceptoid;
}
else if (selectedPerceptoid.isSleeping == false) {
if (perceptoid.receptor.position.magnitude < selectedPerceptoid.receptor.position.magnitude)
selectedPerceptoid = perceptoid;
}
}
if (selectedPerceptoid == null) {
Debug.Log("No perceptoid selected, stimulus is ignored");
return;
}
Debug.Log($"Stimulus {thingId} {selectedPerceptoid.thingId}");
selectedPerceptoid.UpdateState(this.thingId, this.localPosition);
}
}

View File

@ -40,11 +40,9 @@ public class SensoryNeuroid : Neuroid {
public SensoryNeuroid(NanoBrainObj brain, int thingId, string name = "sensor") : base(brain, name) {
this.name = name + ": position";
this.receptor = new Receptor {
neuroid = this,
//perceptoids[0] = this,
thingType = thingId
};
// this.receptor = new Receptor(this) {
// thingType = thingId
// };
this.velocityNeuroid = new(brain, name + ": velocity");
// The velocity neuroid received position data from this
this.AddReceiver(velocityNeuroid);

View File

@ -237,38 +237,6 @@ public class NanoBrainInspector : Editor {
DrawNucleus(this.currentNucleus, position, this.currentNucleus.outputValue.magnitude, 20);
}
private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) {
if (nucleus.isSleeping)
Handles.color = Color.darkRed;
else {
float brightness = nucleus.outputValue.magnitude / maxValue;
Handles.color = new Color(brightness, brightness, brightness);
}
Handles.DrawSolidDisc(position, Vector3.forward, size);
Vector3 labelPos = position - 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, nucleus.name, style);
Rect neuronRect = new(position.x - size, position.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)) {
// Process Hover
HandleMouseHover(nucleus, neuronRect);
// Process click
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
HandleClicked(nucleus);
}
}
}
private void DrawReceivers(Nucleus nucleus, Vector3 parentPos, float size) {
int nodeCount = nucleus.receivers.Count;
@ -290,6 +258,8 @@ public class NanoBrainInspector : Editor {
int row = 0;
foreach (Receiver receiver in nucleus.receivers) {
Nucleus receiverNucleus = receiver.nucleus;
if (receiverNucleus == null)
continue;
Vector3 pos = new(100, margin + row * spacing, 0.0f);
Handles.color = Color.white;
@ -331,104 +301,68 @@ public class NanoBrainInspector : Editor {
}
}
/*
private void DrawLayer(NeuroidLayer layer) {
int nodeCount = layer.neuroids.Count;
// Determine the maximum value in this layer
// This is used to 'scale' the output value colors of the nuclei
float maxValue = 0;
foreach (Nucleus nucleus in layer.neuroids) {
if (nucleus is Neuroid neuroid) {
float value = neuroid.outputValue.magnitude;
if (value > maxValue)
maxValue = value;
}
private void DrawNucleus(Nucleus nucleus, Vector3 position, float maxValue, float size) {
if (nucleus.isSleeping)
Handles.color = Color.darkRed;
else {
float brightness = nucleus.outputValue.magnitude / maxValue;
Handles.color = new Color(brightness, brightness, brightness);
}
Handles.DrawSolidDisc(position, Vector3.forward, size);
Vector3 labelPos = position - 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, nucleus.name, style);
// Determine the spacing of the nuclei in the layer
float spacing = 400f / nodeCount;
float margin = 10 + spacing / 2;
foreach (Nucleus layerNucleus in layer.neuroids) {
Vector2Int layerNeuroidPos = this.neuroidPositions[layerNucleus];
Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f);
float inputSpacing = 400f / layerNucleus.synapses.Count;
float inputMargin = 10 + inputSpacing / 2;
int minStale = 10000;
foreach (Synapse synapse in layerNucleus.synapses) {
Nucleus nucleus = synapse.nucleus;
if (nucleus != null) {
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);
Handles.color = Color.white;
Handles.DrawLine(parentPos, pos);
}
}
if (nucleus is Neuroid neuroid && neuroid.stale < minStale)
minStale = neuroid.stale;
}
}
float size = 20;
if (layerNucleus == this.currentNucleus) {
Handles.color = Color.white;
Handles.DrawSolidDisc(parentPos, Vector3.forward, size + 2);
}
DrawNucleus(layerNucleus, parentPos, maxValue, size);
// if (layerNucleus.isSleeping)
// Handles.color = Color.darkRed;
// else {
// float brightness = layerNucleus.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, layerNucleus.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)) {
// Process Hover
HandleMouseHover(layerNucleus, neuronRect);
// Process click
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
HandleClicked(layerNucleus);
}
Rect neuronRect = new(position.x - size, position.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)) {
// Process Hover
HandleMouseHover(nucleus, neuronRect);
// Process click
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
HandleClicked(nucleus);
}
}
}
*/
private void HandleMouseHover(Nucleus neuroid, Rect rect) {
private void HandleMouseHover(Nucleus nucleus, Rect rect) {
GUIContent tooltip;
if (neuroid is SensoryNeuroid sensoryNeuroid) {
if (nucleus is SensoryNeuroid sensoryNeuroid) {
tooltip = new(
$"{sensoryNeuroid.name}" +
$"\nThing {sensoryNeuroid.receptor.thingType}" +
$"\nValue: {neuroid.outputValue}" +
$"\nStale: {neuroid.stale}");
$"\nValue: {nucleus.outputValue}" +
$"\nStale: {nucleus.stale}");
}
else if (nucleus is Perceptoid perceptoid) {
if (perceptoid.receptor != null) {
tooltip = new(
$"{perceptoid.name}" +
$"\nType {perceptoid.receptor.thingType}" +
$" Thing {perceptoid.thingId}" +
$"\nValue: {nucleus.outputValue}");
}
else {
tooltip = new(
$"{perceptoid.name}" +
$"\nThing {perceptoid.thingId}" +
$"\nValue: {nucleus.outputValue}");
}
}
else {
tooltip = new(
$"{neuroid.name}" +
$"\nsynapse count {neuroid.synapses.Count}" +
$"\nValue: {neuroid.outputValue}" +
$"\nStale: {neuroid.stale}");
$"{nucleus.name}" +
$"\nsynapse count {nucleus.synapses.Count}" +
$"\nValue: {nucleus.outputValue}" +
$"\nStale: {nucleus.stale}");
}
Vector2 mousePosition = Event.current.mousePosition;
@ -445,7 +379,6 @@ public class NanoBrainInspector : Editor {
BuildLayers();
}
void DrawInspector(VisualElement inspectorContainer) {
if (inspectorContainer == null)
return;
@ -518,9 +451,14 @@ public class NanoBrainInspector : Editor {
}
protected virtual void DeleteNeuron(Nucleus nucleus) {
this.currentNucleus = nucleus.receivers[0].nucleus;
this.currentNucleus = nucleus.brain.root;
foreach (Receiver receiver in nucleus.receivers) {
if (receiver.nucleus != null) {
this.currentNucleus = receiver.nucleus;
break;
}
}
Nucleus.Delete(nucleus);
//Rebuild(inspectorContainer);
BuildLayers();
}

View File

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

View File

@ -49,4 +49,5 @@ MonoBehaviour:
inverse: 0
exponent: 1
thingType: 1
thingId: 0
rootId: -1707533328

View File

@ -23,7 +23,7 @@ MonoBehaviour:
- nucleusId: -112538112
weight: 1
- nucleusId: 1938577052
weight: 1
weight: 10
receivers: []
nucleusType:
average: 0
@ -43,9 +43,9 @@ MonoBehaviour:
- id: 1938577052
_name: Cohesion
synapses:
- nucleusId: -1408496896
- nucleusId: -1420275136
weight: 1
- nucleusId: -133566816
- nucleusId: -1266532688
weight: 1
receivers:
- nucleusId: -1707533328
@ -64,7 +64,8 @@ MonoBehaviour:
inverse: 0
exponent: 1
thingType: 1
- id: -1408496896
thingId: 0
- id: -1420275136
_name: Boid1
synapses: []
receivers:
@ -74,15 +75,16 @@ MonoBehaviour:
inverse: 0
exponent: 1
thingType: 2
- id: -133566816
thingId: 0
- id: -1266532688
_name: Boid2
synapses: []
receivers:
- nucleusId: 27651644
- nucleusId: 1938577052
nucleusType: Perceptoid
average: 0
inverse: 0
exponent: 1
thingType: 2
thingId: 0
rootId: -1707533328