More nucleus like neurons

This commit is contained in:
Pascal Serrarens 2025-12-02 17:34:05 +01:00
parent 88bf20b9c2
commit 9a6ae0e071
8 changed files with 221 additions and 173 deletions

View File

@ -5,13 +5,13 @@ using System.Collections.Generic;
public class NeuroidLayer { public class NeuroidLayer {
public int ix = 0; public int ix = 0;
public List<Neuroid> neuroids = new(); public List<Nucleus> neuroids = new();
} }
public class GraphEditorWindow : EditorWindow { public class GraphEditorWindow : EditorWindow {
private Neuroid currentNeuroid; private Nucleus currentNucleus;
private List<Neuroid> allNeuroids; private List<Neuroid> allNeuroids;
private Dictionary<Neuroid, Vector2Int> neuroidPositions = new(); private Dictionary<Nucleus, Vector2Int> neuroidPositions = new();
private List<NeuroidLayer> layers = new(); private List<NeuroidLayer> layers = new();
@ -21,7 +21,58 @@ public class GraphEditorWindow : EditorWindow {
SelectNeuron(); SelectNeuron();
} }
private void BuildLayers(List<Neuroid> neuroids) { 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 BuildLayers() {
// A temporary list to track what's been added to layers
this.layers = new();
int layerIx = 0;
Nucleus selectedNucleus = this.currentNucleus;
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 };
int six = 0;
foreach (Synapse synapse in selectedNucleus.synapses.Values) {
Debug.Log($"Synapse {six}");
Nucleus input = synapse.neuroid;
if (input != null) {
AddToLayer(currentLayer, input);
Debug.Log($"layer {layerIx} nucleus {input.name}");
}
six++;
}
if (currentLayer.neuroids.Count > 0) {
this.layers.Add(currentLayer);
}
}
private void BuildLayers_old(List<Neuroid> neuroids) {
if (neuroids == null) if (neuroids == null)
return; return;
@ -41,10 +92,11 @@ public class GraphEditorWindow : EditorWindow {
if (neuronVisited.Contains(neuroid)) if (neuronVisited.Contains(neuroid))
continue; continue;
if (neuroid.IsStale()) { // if (neuroid.IsStale()) {
neuronVisited.Add(neuroid); // Debug.Log($"neuron {neuroid.name} is stale {neuroid.stale}");
continue; // neuronVisited.Add(neuroid);
} // continue;
// }
// If the output neuroid is visited // If the output neuroid is visited
// Note: this does not yet work for multiple outputs yet (see the use of First()) // Note: this does not yet work for multiple outputs yet (see the use of First())
@ -92,7 +144,7 @@ public class GraphEditorWindow : EditorWindow {
} }
private void DrawGraph() { private void DrawGraph() {
if (currentNeuroid == null) if (currentNucleus == null)
return; return;
foreach (NeuroidLayer layer in layers) foreach (NeuroidLayer layer in layers)
@ -103,56 +155,88 @@ public class GraphEditorWindow : EditorWindow {
int column = layer.ix * 100; int column = layer.ix * 100;
int nodeCount = layer.neuroids.Count; int nodeCount = layer.neuroids.Count;
float maxValue = 0; float maxValue = 0;
foreach (Neuroid neuroid in layer.neuroids) { foreach (Nucleus nucleus in layer.neuroids) {
float value = neuroid.outputValue.magnitude; if (nucleus is Neuroid neuroid) {
if (value > maxValue) float value = neuroid.outputValue.magnitude;
maxValue = value; if (value > maxValue)
maxValue = value;
}
} }
float spacing = 200f / nodeCount; float spacing = 400f / nodeCount;
float margin = 100 + spacing / 2; float margin = 100 + spacing / 2;
foreach (Neuroid layerNeuroid in layer.neuroids) { foreach (Nucleus layerNucleus in layer.neuroids) {
Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid]; if (layerNucleus is Neuroid layerNeuroid) {
Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); Vector2Int layerNeuroidPos = this.neuroidPositions[layerNeuroid];
Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f);
int i = 0; int i = 0;
float inputSpacing = 200f / layerNeuroid.synapses.Count; float inputSpacing = 400f / layerNeuroid.synapses.Count;
float inputMargin = 100 + inputSpacing / 2; float inputMargin = 100 + inputSpacing / 2;
foreach (Synapse synapse in layerNeuroid.synapses.Values) { foreach (Synapse synapse in layerNeuroid.synapses.Values) {
if (synapse.neuroid != null) { if (synapse.neuroid != null) {
if (this.neuroidPositions.ContainsKey(synapse.neuroid)) { if (this.neuroidPositions.ContainsKey(synapse.neuroid)) {
Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid]; Vector2Int inputNeuroidPos = this.neuroidPositions[synapse.neuroid];
Vector3 pos = new(100 + inputNeuroidPos.x * 100, inputMargin + inputNeuroidPos.y * inputSpacing, 0.0f); 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; float brightness = synapse.weight / 10.0f;
Handles.color = new Color(brightness, brightness, brightness); Handles.color = new Color(brightness, brightness, brightness);
Handles.DrawLine(parentPos, pos); 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);
Event e = Event.current;
if (e != null && neuronRect.Contains(e.mousePosition)) {
HandleMouseHover(layerNeuroid, neuronRect);
// Process click
if (e.type == EventType.MouseDown && e.button == 0) {
// Consume the event so the scene doesn't also handle it
e.Use();
HandleDiscClicked(layerNeuroid);
}
}
i++;
} }
float size = layerNeuroid.outputValue.magnitude / maxValue * 20;
if (layerNeuroid.IsStale())
Handles.color = Color.yellow;
else
Handles.color = Color.white;
Handles.DrawSolidDisc(parentPos, Vector3.forward, size);
Rect neuronRect = new(parentPos.x - size, parentPos.y - size, size * 2, size * 2);
if (neuronRect.Contains(Event.current.mousePosition))
HandleMouseHover(layerNeuroid, neuronRect);
i++;
} }
} }
private void HandleMouseHover(Neuroid neuroid, Rect rect) { private void HandleMouseHover(Neuroid neuroid, Rect rect) {
// Draw the tooltip GUIContent tooltip;
GUIContent tooltip = new( if (neuroid is SensoryNeuroid sensoryNeuroid) {
$"{neuroid.name}" + tooltip = new(
$"\nsynapse count {neuroid.synapses.Count}" + $"{sensoryNeuroid.name}" +
$"\nValue: {neuroid.outputValue}" + $"\nThing {sensoryNeuroid.receptor.thingId}" +
$"\nStale: {neuroid.stale}"); $"\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; Vector2 mousePosition = Event.current.mousePosition;
// Display tooltip with some offset // Display tooltip with some offset
@ -162,6 +246,10 @@ public class GraphEditorWindow : EditorWindow {
GUI.Box(tooltipRect, tooltip); GUI.Box(tooltipRect, tooltip);
} }
private void HandleDiscClicked(Nucleus nucleus) {
this.currentNucleus = nucleus;
BuildLayers();
}
// Update node colors based on selected GameObjects // Update node colors based on selected GameObjects
private void SelectNeuron() { private void SelectNeuron() {
@ -175,15 +263,15 @@ public class GraphEditorWindow : EditorWindow {
return; return;
Neuroid neuroid = boid.totalForce; Neuroid neuroid = boid.totalForce;
this.currentNeuroid = neuroid; this.currentNucleus = neuroid;
if (neuroid == null) if (neuroid == null)
this.allNeuroids = new(); this.allNeuroids = new();
else else
this.allNeuroids = neuroid.net.neuroids; this.allNeuroids = neuroid.net.neuroids;
//Debug.Log($"Neuroncount = {this.allNeuroids.Count}"); Debug.Log($"Neuroncount = {this.allNeuroids.Count}");
BuildLayers(this.allNeuroids); BuildLayers();
Debug.Log($"Layercount = {this.layers.Count}"); Debug.Log($"Layercount = {this.layers.Count}");
} }

View File

@ -3,12 +3,12 @@ using UnityEngine;
using System.Linq; using System.Linq;
public class Synapse { public class Synapse {
public Synapse(Neuroid neuroid, Vector3 value, float weight) { public Synapse(Nucleus neuroid, Vector3 value, float weight) {
this.neuroid = neuroid; this.neuroid = neuroid;
this.value = value; this.value = value;
this.weight = weight; this.weight = weight;
} }
public Neuroid neuroid; public Nucleus neuroid;
public Vector3 value; public Vector3 value;
public float weight; public float weight;
} }
@ -23,20 +23,17 @@ public class NeuroidNetwork {
public void Update() { public void Update() {
foreach (Neuroid neuroid in neuroids) { foreach (Neuroid neuroid in neuroids) {
neuroid.stale++; neuroid.stale++;
if (neuroid.IsStale())
neuroid.outputValue = Vector3.zero;
} }
} }
} }
public class Neuroid : Nucleus { public class Neuroid : Nucleus {
public string name;
public int stale = 0; public int stale = 0;
// public readonly Dictionary<Neuroid, Synapse> synapses = new(); //public Vector3 outputValue;
public Vector3 outputValue;
// public HashSet<Neuroid> outputNeuroids = new();
public bool average = false; public bool average = false;
//public bool quadratic = false; //public bool quadratic = false;
@ -45,11 +42,12 @@ public class Neuroid : Nucleus {
public NeuroidNetwork net; public NeuroidNetwork net;
public Neuroid(NeuroidNetwork net, string name) : base(net) { public Neuroid(NeuroidNetwork net, string name) : base(name) {
this.net = net; this.net = net;
this.name = name;
if (this.net != null) if (this.net != null)
this.net.neuroids.Add(this); this.net.neuroids.Add(this);
else
Debug.LogError("No neuroid network");
} }
public void AddSynapse(Neuroid input) { public void AddSynapse(Neuroid input) {
@ -129,8 +127,14 @@ public class Neuroid : Nucleus {
protected virtual void UpdateState() { protected virtual void UpdateState() {
Vector3 result = Vector3.zero; Vector3 result = Vector3.zero;
foreach (Synapse synapse in this.synapses.Values) { foreach (Synapse synapse in this.synapses.Values) {
// if (synapse.neuroid == null)
// continue;
Vector3 direction = synapse.value.normalized; Vector3 direction = synapse.value.normalized;
float magnitude = synapse.value.magnitude; float magnitude = synapse.value.magnitude;
// Vector3 direction = synapse.neuroid.outputValue.normalized;
// float magnitude = synapse.neuroid.outputValue.magnitude;
magnitude = synapse.weight * Mathf.Pow(magnitude, exponent); magnitude = synapse.weight * Mathf.Pow(magnitude, exponent);
if (inverse) if (inverse)
magnitude = 1 / magnitude; magnitude = 1 / magnitude;

View File

@ -1,26 +1,21 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine;
public class Nucleus { public class Nucleus {
//public Neuroid output; public string name;
public readonly Dictionary<Neuroid, Synapse> synapses = new();
public readonly Dictionary<Nucleus, Synapse> synapses = new();
public HashSet<Neuroid> outputNeuroids = new(); public HashSet<Neuroid> outputNeuroids = new();
public virtual Vector3 outputValue {get; set; }
public int layerIx; public int layerIx;
public Nucleus(string name) {
public Nucleus(NeuroidNetwork neuroidNet) { this.name = name;
//this.output = new(neuroidNet, "Nucleus output");
} }
public virtual void AddReceiver(Neuroid receiver) { public virtual void AddReceiver(Neuroid receiver) {
//this.output.AddReceiver(receiver);
this.outputNeuroids.Add(receiver); this.outputNeuroids.Add(receiver);
receiver.synapses[this] = new(this, Vector3.zero, 1.0f);
} }
// public void GetInputFrom(Neuroid input, float weight = 1.0f) {
// input.AddReceiver(this);
// this.synapses[input] = new(input, Vector3.zero, weight);
// }
} }

View File

@ -15,7 +15,7 @@ public class Perception : Nucleus {
public HashSet<Receiver> positionReceivers { get; protected set; } public HashSet<Receiver> positionReceivers { get; protected set; }
public HashSet<Receiver> velocityReceivers { get; protected set; } public HashSet<Receiver> velocityReceivers { get; protected set; }
public Perception(NeuroidNetwork neuroidNet) : base(neuroidNet) { public Perception(NeuroidNetwork neuroidNet) : base("Perception") {
this.neuroidNet = neuroidNet; this.neuroidNet = neuroidNet;
this.positionReceivers = new(); this.positionReceivers = new();
this.velocityReceivers = new(); this.velocityReceivers = new();
@ -48,9 +48,9 @@ public class Perception : Nucleus {
} }
} }
public void ProcessStimulus(int thingId, int thingType, Vector3 localPosition) { public void ProcessStimulus(int thingId, int thingType, Vector3 localPosition, string name = "Sensing") {
int availableIx = -1; int availableIx = -1;
SensoryNeuroid leastInterestingNeuroid = null; int leastInterestingIx = -1;
for (int i = 0; i < sensoryNeuroids.Length; i++) { for (int i = 0; i < sensoryNeuroids.Length; i++) {
if (sensoryNeuroids[i] == null || sensoryNeuroids[i].IsStale()) if (sensoryNeuroids[i] == null || sensoryNeuroids[i].IsStale())
availableIx = i; availableIx = i;
@ -59,39 +59,28 @@ public class Perception : Nucleus {
return; return;
} }
if (sensoryNeuroids[i] != null) { if (sensoryNeuroids[i] != null) {
if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude) if (leastInterestingIx == -1 || sensoryNeuroids[leastInterestingIx].receptor.position.magnitude > sensoryNeuroids[i].receptor.position.magnitude)
leastInterestingNeuroid = sensoryNeuroids[i]; leastInterestingIx = i;
} }
} }
if (availableIx == -1)
availableIx = leastInterestingIx;
if (availableIx != -1) { if (availableIx != -1) {
if (sensoryNeuroids[availableIx] != null) { // Debug.Log($"new receptor for {thingId}");
// Debug.Log($"revived receptor {availableIx} for {thingId}"); SensoryNeuroid neuroid = new(neuroidNet, thingId) { name = name };
sensoryNeuroids[availableIx].receptor.thingId = thingId; foreach (Receiver receiver in positionReceivers) {
sensoryNeuroids[availableIx].receptor.position = localPosition; if (receiver.thingType == 0 || receiver.thingType == thingType)
receiver.neuroid.GetInputFrom(neuroid);
} }
else { foreach (Receiver receiver in velocityReceivers) {
// Debug.Log($"new receptor for {thingId}"); if (receiver.thingType == 0 || receiver.thingType == thingType)
SensoryNeuroid neuroid = new(neuroidNet, thingId); receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid);
foreach (Receiver receiver in positionReceivers) {
if (receiver.thingType == 0 || receiver.thingType == thingType)
receiver.neuroid.GetInputFrom(neuroid);
}
foreach (Receiver receiver in velocityReceivers) {
if (receiver.thingType == 0 || receiver.thingType == thingType)
receiver.neuroid.GetInputFrom(neuroid.velocityNeuroid);
}
sensoryNeuroids[availableIx] = neuroid;
neuroid.receptor.position = localPosition;
} }
}
else if (leastInterestingNeuroid != null) {
//Debug.Log($"replaced receptor {leastInterestingNeuroid.thingId} for {thingId}");
leastInterestingNeuroid.receptor.thingId = thingId;
leastInterestingNeuroid.receptor.position = localPosition;
}
//Debug.LogWarning($"No available receptor for {id}"); sensoryNeuroids[availableIx] = neuroid;
neuroid.receptor.position = localPosition;
}
} }
public void RemoveStimulus(int thingId) { public void RemoveStimulus(int thingId) {
@ -103,6 +92,6 @@ public class Perception : Nucleus {
return; return;
} }
} }
} }
} }

View File

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

View File

@ -21,15 +21,10 @@ public class Boid : MonoBehaviour {
private Bounds innerBounds; private Bounds innerBounds;
private Bounds outerBounds; private Bounds outerBounds;
readonly Collider[] results = new Collider[10];
public NeuroidNetwork neuroidNet = new(); public NeuroidNetwork neuroidNet = new();
public Perception perception; public Perception perception;
public Neuroid cohesion;
public Neuroid alignment; public Nucleus behaviour;
public Neuroid avoidance;
// public Neuroid boundary;
public Roaming roaming;
public Neuroid totalForce; public Neuroid totalForce;
@ -45,53 +40,34 @@ public class Boid : MonoBehaviour {
perception = new Perception(neuroidNet); perception = new Perception(neuroidNet);
// cohesion = new(neuroidNet, "Cohesion"); //behaviour = new Roaming(neuroidNet, perception, sc);
// perception.SendPositions(cohesion, 1.0f, BoidType); behaviour = new Swarming(neuroidNet, perception, sc);
// alignment = new(neuroidNet, "Alignment") { average = true };
// perception.SendVelocities(alignment);
// avoidance = new(neuroidNet, "Separation") { inverse = true };
// perception.SendPositions(avoidance, sc.avoidanceForce);
//boundary = new(neuroidNet, "Boundary");
roaming = new(neuroidNet, perception, sc);
totalForce = new(neuroidNet, "Total"); totalForce = new(neuroidNet, "Total");
//totalForce.GetInputFrom(alignment, sc.alignmentForce); behaviour.AddReceiver(totalForce);
//totalForce.GetInputFrom(cohesion, sc.cohesionForce);
// totalForce.GetInputFrom(avoidance, -sc.avoidanceForce);
//totalForce.GetInputFrom(boundary, sc.boundaryForce);
roaming.AddReceiver(totalForce);
} }
void Update() { void Update() {
// Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance);
// foreach (Collider c in results) { foreach (Collider c in results) {
// if (c == null) if (c as CapsuleCollider != null) {
// continue; Boid neighbour = c.GetComponentInParent<Boid>();
if (neighbour == null || neighbour == this)
continue;
// if (c as CapsuleCollider != null) { Vector3 localPosition = neighbour.transform.position - this.transform.position;
// Boid neighbour = c.GetComponentInParent<Boid>();
// if (neighbour == null || neighbour == this)
// continue;
// Vector3 localPosition = neighbour.transform.position - this.transform.position; int thingId = neighbour.GetInstanceID();
// if (debug) perception.ProcessStimulus(thingId, BoidType, localPosition); //, neighbour.gameObject.name);
// Debug.Log($" distance {localPosition.magnitude}"); }
}
// int thingId = neighbour.GetInstanceID();
// perception.ProcessStimulus(thingId, localPosition);
// }
// }
if (!innerBounds.Contains(this.transform.position)) { if (!innerBounds.Contains(this.transform.position)) {
Vector3 point = this.transform.position; Vector3 point = this.transform.position;
Vector3 pointOnBounds = innerBounds.ClosestPoint(point); Vector3 pointOnBounds = innerBounds.ClosestPoint(point);
Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed;
Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace);
perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace); perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace, "Boundary");
} }
else { else {
perception.RemoveStimulus(777); perception.RemoveStimulus(777);

View File

@ -1,18 +1,11 @@
public class Roaming : Nucleus { public class Roaming : Nucleus {
public float avoidanceForce;
public Neuroid avoidance; public Neuroid avoidance;
public Neuroid output; public Neuroid output;
public const int BoundaryType = 1;
public const int BoidType = 2;
public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) {
this.avoidanceForce = sc.avoidanceForce;
public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Roaming nucleus") {
avoidance = new(neuroidNet, "Avoidance") { inverse = true }; avoidance = new(neuroidNet, "Avoidance") { inverse = true };
perception.SendPositions(avoidance); perception.SendPositions(avoidance, 1.0f, 1);
this.output = new(neuroidNet, "Roaming"); this.output = new(neuroidNet, "Roaming");
output.GetInputFrom(avoidance, -sc.avoidanceForce); output.GetInputFrom(avoidance, -sc.avoidanceForce);

View File

@ -1,31 +1,34 @@
public class Swarming : Nucleus { using UnityEngine;
//public Perception perception;
public class Swarming : Nucleus {
public Neuroid cohesion; public Neuroid cohesion;
public Neuroid alignment; public Neuroid alignment;
public Neuroid avoidance; public Neuroid avoidance;
public Neuroid boundary;
public Neuroid output; public Neuroid output;
public override Vector3 outputValue { get => output.outputValue; set => output.outputValue = value; }
public const int BoundaryType = 1; public const int BoundaryType = 1;
public const int BoidType = 2; public const int BoidType = 2;
public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) { public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base("Swarming Nucleus") {
cohesion = new(neuroidNet, "Cohesion"); this.cohesion = new(neuroidNet, "Cohesion");
perception.SendPositions(cohesion, 1.0f, BoidType); perception.SendPositions(this.cohesion, 1.0f, BoidType);
alignment = new(neuroidNet, "Alignment") { average = true }; this.alignment = new(neuroidNet, "Alignment") { average = true };
perception.SendVelocities(alignment); perception.SendVelocities(this.alignment, 1.0f, BoidType);
avoidance = new(neuroidNet, "Separation") { inverse = true }; this.avoidance = new(neuroidNet, "Avoidance") { inverse = true };
perception.SendPositions(avoidance, sc.avoidanceForce); perception.SendPositions(this.avoidance);
boundary = new(neuroidNet, "Boundary");
this.output = new(neuroidNet, "Swarming"); this.output = new(neuroidNet, "Swarming");
output.GetInputFrom(alignment, sc.alignmentForce); //this.output.GetInputFrom(alignment, sc.alignmentForce);
output.GetInputFrom(cohesion, sc.cohesionForce); this.output.GetInputFrom(cohesion, sc.cohesionForce);
output.GetInputFrom(avoidance, -sc.avoidanceForce); this.output.GetInputFrom(avoidance, -sc.avoidanceForce);
output.GetInputFrom(boundary, sc.boundaryForce); }
}}
public override void AddReceiver(Neuroid receiver) {
this.output.AddReceiver(receiver);
}
}