Move more towards pure neuroids

This commit is contained in:
Pascal Serrarens 2025-11-28 17:15:49 +01:00
parent 7ce787f5db
commit fdabad2895
7 changed files with 113 additions and 201 deletions

View File

@ -37,15 +37,19 @@ public class GraphEditorWindow : EditorWindow {
int neuroidIx = 0; int neuroidIx = 0;
foreach (Neuroid neuroid in neuroids) { foreach (Neuroid neuroid in neuroids) {
// Skip neurons we already processed
if (neuronVisited.Contains(neuroid))
continue;
if (neuroid.IsStale()) { if (neuroid.IsStale()) {
neuronVisited.Add(neuroid); neuronVisited.Add(neuroid);
continue; continue;
} }
// If this neuroid is not visited while its 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())
if (!neuronVisited.Contains(neuroid) && (neuroid.outputNeuroids.Count == 0 || if (neuroid.outputNeuroids.Count == 0 // make sure the root neuroids are processed directly
(neuronVisited.Contains(neuroid.outputNeuroids.First()) && neuroid.outputNeuroids.First().layerIx == layerIx - 1))) { || (neuronVisited.Contains(neuroid.outputNeuroids.First()) && neuroid.outputNeuroids.First().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; neuroid.layerIx = layerIx;
@ -111,9 +115,9 @@ public class GraphEditorWindow : EditorWindow {
Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f); Vector3 parentPos = new(100 + layerNeuroidPos.x * 100, margin + layerNeuroidPos.y * spacing, 0.1f);
int i = 0; int i = 0;
float inputSpacing = 200f / layerNeuroid.newSynapses.Count; float inputSpacing = 200f / layerNeuroid.synapses.Count;
float inputMargin = 100 + inputSpacing / 2; float inputMargin = 100 + inputSpacing / 2;
foreach (Synapse synapse in layerNeuroid.newSynapses.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)) {
@ -145,7 +149,7 @@ public class GraphEditorWindow : EditorWindow {
// Draw the tooltip // Draw the tooltip
GUIContent tooltip = new( GUIContent tooltip = new(
$"{neuroid.name}" + $"{neuroid.name}" +
$"\nsynapse count {neuroid.newSynapses.Count}" + $"\nsynapse count {neuroid.synapses.Count}" +
$"\nValue: {neuroid.outputValue}" + $"\nValue: {neuroid.outputValue}" +
$"\nStale: {neuroid.stale}"); $"\nStale: {neuroid.stale}");

View File

@ -16,8 +16,8 @@ public class Synapse {
public class NeuroidNetwork { public class NeuroidNetwork {
public List<Neuroid> neuroids = new(); public List<Neuroid> neuroids = new();
public Neuroid AddNeuron() { public Neuroid AddNeuron(string name) {
Neuroid neuroid = new(this); Neuroid neuroid = new(this, name);
return neuroid; return neuroid;
} }
@ -29,35 +29,33 @@ public class NeuroidNetwork {
} }
public class Neuroid { public class Neuroid {
//public int id;
public string name; public string name;
public int layerIx; public int layerIx;
public int stale = 0; public int stale = 0;
public readonly Dictionary<Neuroid, Synapse> newSynapses = new(); public readonly Dictionary<Neuroid, Synapse> synapses = new();
public Vector3 outputValue; public Vector3 outputValue;
public HashSet<Neuroid> outputNeuroids = new(); public HashSet<Neuroid> outputNeuroids = new();
public enum Mode { public bool average = false;
Sum, //public bool quadratic = false;
Average, public bool inverse = false;
} public float exponent = 1.0f;
public Mode mode = Mode.Sum;
public NeuroidNetwork net; public NeuroidNetwork net;
public Neuroid(NeuroidNetwork net) { public Neuroid(NeuroidNetwork net, string 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);
} }
public void AddSynapse(Neuroid input) { public void AddSynapse(Neuroid input) {
input.AddReceiver(this); input.AddReceiver(this);
this.newSynapses[input] = new(input, Vector3.zero, 1.0f); this.synapses[input] = new(input, Vector3.zero, 1.0f);
} }
public void AddReceiver(Neuroid receiver) { public void AddReceiver(Neuroid receiver) {
@ -65,84 +63,77 @@ public class Neuroid {
} }
public void ResetWeights() { public void ResetWeights() {
foreach (Synapse synapse in this.newSynapses.Values) foreach (Synapse synapse in this.synapses.Values)
synapse.weight = 1.0f; synapse.weight = 1.0f;
} }
public void SetWeight(Neuroid input, float weight) { public void SetWeight(Neuroid input, float weight) {
if (this.newSynapses.ContainsKey(input)) { if (this.synapses.ContainsKey(input)) {
this.newSynapses[input].weight = weight; this.synapses[input].weight = weight;
} }
else { else {
this.newSynapses[input] = new(input, Vector3.zero, weight); this.synapses[input] = new(input, Vector3.zero, weight);
} }
} }
public void GetInputFrom(Neuroid input, float weight = 1.0f) { public void GetInputFrom(Neuroid input, float weight = 1.0f) {
input.AddReceiver(this); input.AddReceiver(this);
this.newSynapses[input] = new(input, Vector3.zero, weight); this.synapses[input] = new(input, Vector3.zero, weight);
} }
public void SetInput(Neuroid input, Vector3 value) { public void SetInput(Neuroid input, Vector3 value) {
if (this.newSynapses.ContainsKey(input)) { if (this.synapses.ContainsKey(input)) {
Synapse synapse = this.newSynapses[input]; Synapse synapse = this.synapses[input];
synapse.value = value; synapse.value = value;
} }
else else
this.newSynapses[input] = new(null, value, 1.0f); this.synapses[input] = new(null, value, 1.0f);
UpdateState(); UpdateState();
} }
public void SetInput(Neuroid input, Vector3 value, float weight) { public void SetInput(Neuroid input, Vector3 value, float weight) {
if (this.newSynapses.ContainsKey(input)) { if (this.synapses.ContainsKey(input)) {
Synapse synapse = this.newSynapses[input]; Synapse synapse = this.synapses[input];
synapse.value = value; synapse.value = value;
synapse.weight = weight; synapse.weight = weight;
} }
else else
this.newSynapses[input] = new(null, value, weight); this.synapses[input] = new(null, value, weight);
UpdateState();
}
public readonly Dictionary<int, Neuroid> fakeNeuroids = new();
public void SetInput(int thingId, Vector3 value, float weight, NeuroidNetwork net) {
if (fakeNeuroids.ContainsKey(thingId)) {
Neuroid fakeInput = fakeNeuroids[thingId];
Synapse synapse = this.newSynapses[fakeInput];
synapse.value = value;
synapse.weight = weight;
}
else {
fakeNeuroids[thingId] = new(net);
this.newSynapses[fakeNeuroids[thingId]] = new (null, value, weight);
}
UpdateState(); UpdateState();
} }
// public readonly Dictionary<int, Neuroid> 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() { protected virtual void UpdateState() {
Vector3 sum = Vector3.zero; Vector3 result = Vector3.zero;
foreach (Synapse synapse in this.newSynapses.Values) foreach (Synapse synapse in this.synapses.Values) {
sum += synapse.value * synapse.weight; Vector3 direction = synapse.value.normalized;
float magnitude = synapse.value.magnitude;
this.outputValue = Activation(sum); magnitude = synapse.weight * Mathf.Pow(magnitude, exponent);
foreach (Neuroid neuroid in outputNeuroids) { if (inverse)
neuroid?.SetInput(this, this.outputValue); magnitude = 1 / magnitude;
result += direction * magnitude;
} }
this.stale = 0; if (average && this.synapses.Count > 0)
} result /= this.synapses.Count;
Vector3 Activation(Vector3 sum) { this.outputValue = result;
if (this.newSynapses.Count == 0 && mode == Mode.Average) foreach (Neuroid neuroid in outputNeuroids)
Debug.LogWarning($"{this.name} has zero synapses for average"); neuroid.SetInput(this, this.outputValue);
if (float.IsNaN(sum.magnitude)) this.stale = 0;
Debug.LogWarning($"{this.name} sum is nan");
return mode switch {
Mode.Sum => sum,
Mode.Average => sum / this.newSynapses.Count,
_ => sum,
};
//return sum; //(sum.magnitude > 0.5f) ? sum : Vector3.zero;
} }
public bool IsStale() { public bool IsStale() {

View File

@ -3,40 +3,33 @@ using UnityEngine;
public class Perception { public class Perception {
public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7]; public SensoryNeuroid[] sensoryNeuroids = new SensoryNeuroid[7];
//public Neuroid[] velocitySensors = new Neuroid[7];
public NeuroidNetwork neuroidNet { get; protected set; } public NeuroidNetwork neuroidNet { get; protected set; }
public HashSet<Neuroid> receivers { get; protected set; } public HashSet<Neuroid> positionReceivers { get; protected set; }
public HashSet<Neuroid> velocityReceivers { get; protected set; }
public Perception(NeuroidNetwork neuroidNet) { public Perception(NeuroidNetwork neuroidNet) {
this.neuroidNet = neuroidNet; this.neuroidNet = neuroidNet;
this.receivers = new(); this.positionReceivers = new();
this.velocityReceivers = new();
} }
// public void SendOutputTo(Neuroid receiver) { public void SendPositions(Neuroid receiver, float weight = 1.0f) {
// foreach (SensoryNeuroid neuroid in sensoryNeuroids) { positionReceivers.Add(receiver);
// if (neuroid != null) {
// neuroid.AddReceiver(receiver);
// receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f);
// }
// }
// }
public void SendPositions(Neuroid receiver) {
receivers.Add(receiver);
foreach (SensoryNeuroid neuroid in sensoryNeuroids) { foreach (SensoryNeuroid neuroid in sensoryNeuroids) {
if (neuroid != null) { if (neuroid != null) {
neuroid.AddReceiver(receiver); neuroid.AddReceiver(receiver);
receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); receiver.synapses[neuroid] = new (neuroid, Vector3.zero, weight);
} }
} }
} }
public void SendVelocities(Neuroid receiver) { public void SendVelocities(Neuroid receiver) {
receivers.Add(receiver); velocityReceivers.Add(receiver);
foreach (SensoryNeuroid neuroid in sensoryNeuroids) { foreach (SensoryNeuroid neuroid in sensoryNeuroids) {
if (neuroid != null && neuroid.velocityNeuroid != null) { if (neuroid != null && neuroid.velocityNeuroid != null) {
neuroid.velocityNeuroid.AddReceiver(receiver); neuroid.velocityNeuroid.AddReceiver(receiver);
receiver.newSynapses[neuroid] = new (neuroid, Vector3.zero, 1.0f); receiver.synapses[neuroid] = new (neuroid, Vector3.zero, 1.0f);
} }
} }
} }
@ -65,8 +58,10 @@ public class Perception {
else { else {
// Debug.Log($"new receptor for {thingId}"); // Debug.Log($"new receptor for {thingId}");
SensoryNeuroid neuroid = new(neuroidNet, thingId); SensoryNeuroid neuroid = new(neuroidNet, thingId);
foreach (Neuroid receiver in receivers) foreach (Neuroid receiver in positionReceivers)
receiver.GetInputFrom(neuroid); receiver.GetInputFrom(neuroid);
foreach (Neuroid receiver in velocityReceivers)
receiver.GetInputFrom(neuroid.velocityNeuroid);
sensoryNeuroids[availableIx] = neuroid; sensoryNeuroids[availableIx] = neuroid;
neuroid.receptor.position = localPosition; neuroid.receptor.position = localPosition;

View File

@ -7,8 +7,7 @@ public class SensoryNeuroid : Neuroid {
public Receptor receptor; public Receptor receptor;
public VelocityNeuroid velocityNeuroid; public VelocityNeuroid velocityNeuroid;
public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net) { public SensoryNeuroid(NeuroidNetwork net, int thingId) : base(net, "sensory neuroid") {
this.name = "sensory neuroid";
this.receptor = new Receptor { this.receptor = new Receptor {
neuroid = this, neuroid = this,
thingId = thingId thingId = thingId
@ -31,7 +30,7 @@ public class Receptor {
public virtual Vector3 position { public virtual Vector3 position {
get { get {
if (neuroid != null) if (neuroid != null)
return neuroid.newSynapses[neuroid].value; return neuroid.synapses[neuroid].value;
else else
return Vector3.zero; return Vector3.zero;
} }
@ -47,12 +46,12 @@ public class VelocityNeuroid : Neuroid {
private Vector3 lastPosition = Vector3.zero; private Vector3 lastPosition = Vector3.zero;
private float lastValueTime = 0; private float lastValueTime = 0;
public VelocityNeuroid(NeuroidNetwork net) : base(net) { public VelocityNeuroid(NeuroidNetwork net) : base(net, "Velocity") {
} }
protected override void UpdateState() { protected override void UpdateState() {
// Assuming only one synapse for now.... // Assuming only one synapse for now....
Vector3 currentPosition = this.newSynapses.First().Value.value; Vector3 currentPosition = this.synapses.First().Value.value;
float currentValueTime = Time.time; float currentValueTime = Time.time;
float deltaTime = currentValueTime - lastValueTime; float deltaTime = currentValueTime - lastValueTime;

View File

@ -377,7 +377,6 @@ MonoBehaviour:
cohesionForce: 5 cohesionForce: 5
separationForce: 5 separationForce: 5
separationDistance: 0.3 separationDistance: 0.3
bodyForce: 20
perceptionDistance: 1 perceptionDistance: 1
boundaryForce: 5 boundaryForce: 5
spaceSize: {x: 10, y: 10, z: 10} spaceSize: {x: 10, y: 10, z: 10}
@ -394,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: 5 count: 10
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

@ -11,6 +11,8 @@ public class Boid : MonoBehaviour {
public float separationDistance = 0.5f; public float separationDistance = 0.5f;
public float bodyForce = 1; public float bodyForce = 1;
public bool debug = false;
public SwarmControl sc; public SwarmControl sc;
public Vector3 velocity = Vector3.zero; public Vector3 velocity = Vector3.zero;
public Vector3 acceleration = Vector3.zero; public Vector3 acceleration = Vector3.zero;
@ -27,7 +29,7 @@ public class Boid : MonoBehaviour {
public Neuroid cohesion; public Neuroid cohesion;
public Neuroid alignment; public Neuroid alignment;
public Neuroid separation; public Neuroid separation;
public Neuroid target; // public Neuroid target;
public Neuroid boundary; public Neuroid boundary;
public Neuroid totalForce; public Neuroid totalForce;
@ -42,34 +44,28 @@ public class Boid : MonoBehaviour {
bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth); bounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth);
perception = new Perception(neuroidNet); perception = new Perception(neuroidNet);
//neighbourSensor = new(neuroidNet) { name = "Neighbour", id = 879 };
cohesion = new(neuroidNet) { name = "Cohesion", mode = Neuroid.Mode.Sum }; cohesion = new(neuroidNet, "Cohesion");
perception.SendPositions(cohesion); perception.SendPositions(cohesion);
//cohesion.GetInputFrom(neighbourSensor);
alignment = new(neuroidNet) { name = "Alignment", mode = Neuroid.Mode.Average }; alignment = new(neuroidNet, "Alignment") { average = true };
//perception.SendVelocities(alignment); perception.SendVelocities(alignment);
separation = new(neuroidNet) { name = "Separation", mode = Neuroid.Mode.Sum };
target = new(neuroidNet) { name = "Target", mode = Neuroid.Mode.Sum }; separation = new(neuroidNet, "Separation") { inverse = true, exponent = 2 };
boundary = new(neuroidNet) { name = "Boundary", mode = Neuroid.Mode.Sum }; perception.SendPositions(separation, sc.separationForce);
boundary = new(neuroidNet, "Boundary");
totalForce = new(neuroidNet) { name = "Total force", mode = Neuroid.Mode.Sum }; totalForce = new(neuroidNet, "Total");
totalForce.GetInputFrom(alignment, sc.alignmentForce); totalForce.GetInputFrom(alignment, sc.alignmentForce);
totalForce.GetInputFrom(cohesion, sc.cohesionForce); totalForce.GetInputFrom(cohesion, sc.cohesionForce);
totalForce.GetInputFrom(separation, sc.separationForce); totalForce.GetInputFrom(separation, -sc.separationForce);
totalForce.GetInputFrom(target, sc.bodyForce);
totalForce.GetInputFrom(boundary, sc.boundaryForce); totalForce.GetInputFrom(boundary, sc.boundaryForce);
} }
void Update() { void Update() {
Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results);
neighbourCount = 0;
cohesion.ResetWeights();
alignment.ResetWeights();
//separation.ResetWeights();
foreach (Collider c in results) { foreach (Collider c in results) {
if (c == null) if (c == null)
continue; continue;
@ -80,45 +76,40 @@ public class Boid : MonoBehaviour {
continue; continue;
Vector3 localPosition = neighbour.transform.position - this.transform.position; Vector3 localPosition = neighbour.transform.position - this.transform.position;
Vector3 relativeVelocity = neighbour.velocity - this.velocity; if (debug)
Debug.Log($" distance {localPosition.magnitude}");
int thingId = neighbour.GetInstanceID(); int thingId = neighbour.GetInstanceID();
perception.ProcessStimulus(thingId, localPosition); perception.ProcessStimulus(thingId, localPosition);
Vector3 separationForce = -localPosition / localPosition.sqrMagnitude;
// which is equivalent to -(localPosition.normalized / localPosition.magnitude)
separation.SetInput(thingId, separationForce, sc.separationDistance, neuroidNet);
//cohesion.SetInput(thingId, localPosition, sc.cohesionForce);
alignment.SetInput(thingId, relativeVelocity, sc.alignmentForce, neuroidNet);
neighbourCount++;
} }
} }
//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) // // Vector3 outside = distanceOutside; // Vector3.Max(Vector3.zero, distanceOutside);
// Vector3 outside = distanceOutside; // Vector3.Max(Vector3.zero, distanceOutside);
Vector3 below = bounds.min - point; // positive where point < min // Vector3 below = bounds.min - point; // positive where point < min
Vector3 above = point - bounds.max; // positive where point > max // Vector3 above = point - bounds.max; // positive where point > max
// outside distances per axis (0 if inside on that axis) // // outside distances per axis (0 if inside on that axis)
Vector3 outside = Vector3.Max(Vector3.zero, Vector3.Max(below, above)); // Vector3 outside = Vector3.Max(Vector3.zero, Vector3.Max(below, above));
float magnitude = outside.magnitude; // float magnitude = outside.magnitude;
Vector3 direction = (sc.transform.position - this.transform.position).normalized; // Vector3 direction = (sc.transform.position - this.transform.position).normalized;
outside = direction * magnitude; // outside = direction * magnitude;
boundary.SetInput(id, outside, sc.boundaryForce, neuroidNet); // boundary.SetInput(id, outside, sc.boundaryForce, neuroidNet);
// 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;
//Debug.DrawRay(this.transform.position, totalForceVector, Color.magenta); //Debug.DrawRay(this.transform.position, totalForceVector, Color.magenta);
if (this.debug) {
Debug.Log($"Cohesion {cohesion.outputValue.magnitude} separation {separation.outputValue.magnitude} alignment {alignment.outputValue.magnitude}");
}
this.velocity = (1 - sc.inertia) * (totalForceVector * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward); this.velocity = (1 - sc.inertia) * (totalForceVector * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward);
//this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed); //this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed);
@ -132,74 +123,7 @@ public class Boid : MonoBehaviour {
//Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}"); //Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}");
neuroidNet.Update(); neuroidNet.Update();
} }
/*
Receptor GetReceptor(Neuroid perceptionNeuroid, int id) {
int availableIx = -1;
for (int i = 0; i < neighbourSensor.Length; i++) {
if (neighbourSensor[i] == null || neighbourSensor[i].IsStale())
availableIx = i;
else if (neighbourSensor[i].thingId == id)
return neighbourSensor[i].receptor;
}
if (availableIx != -1) {
if (neighbourSensor[availableIx] != null) {
Debug.Log($"revived receptor {availableIx} for {id}");
neighbourSensor[availableIx].thingId = id;
return neighbourSensor[availableIx].receptor;
}
else {
Debug.Log($"new receptor for {id}");
SensoryNeuroid neuroid = new(neuroidNet, id);
perceptionNeuroid.GetInputFrom(neuroid);
neighbourSensor[availableIx] = neuroid;
return neuroid.receptor;
}
}
//Debug.LogWarning($"No available receptor for {id}");
return null;
}
/*
void ProcessStimulus(int thingId, Vector3 value) {
int availableIx = -1;
SensoryNeuroid leastInterestingNeuroid = null;
for (int i = 0; i < neighbourSensor.Length; i++) {
if (neighbourSensor[i] == null || neighbourSensor[i].IsStale())
availableIx = i;
else if (neighbourSensor[i].thingId == thingId) {
neighbourSensor[i].receptor.SetValue(value);
return;
}
if (neighbourSensor[i] != null) {
if (leastInterestingNeuroid == null || leastInterestingNeuroid.receptor.GetValue().magnitude > neighbourSensor[i].receptor.GetValue().magnitude)
leastInterestingNeuroid = neighbourSensor[i];
}
}
if (availableIx != -1) {
if (neighbourSensor[availableIx] != null) {
// Debug.Log($"revived receptor {availableIx} for {thingId}");
neighbourSensor[availableIx].thingId = thingId;
neighbourSensor[availableIx].receptor.SetValue(value);
}
else {
// Debug.Log($"new receptor for {thingId}");
SensoryNeuroid neuroid = new(neuroidNet, thingId);
cohesion.GetInputFrom(neuroid);
neighbourSensor[availableIx] = neuroid;
neuroid.receptor.SetValue(value);
}
}
else if (leastInterestingNeuroid != null) {
//Debug.Log($"replaced receptor {leastInterestingNeuroid.thingId} for {thingId}");
leastInterestingNeuroid.thingId = thingId;
leastInterestingNeuroid.receptor.SetValue(value);
}
//Debug.LogWarning($"No available receptor for {id}");
}
*/
void OnDrawGizmosSelected() { void OnDrawGizmosSelected() {
Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance);
} }

View File

@ -10,7 +10,7 @@ public class SwarmControl : MonoBehaviour
public float cohesionForce = 10.0f; public float cohesionForce = 10.0f;
public float separationForce = 5.0f; public float separationForce = 5.0f;
public float separationDistance = 0.5f; public float separationDistance = 0.5f;
public float bodyForce = 20; // public float bodyForce = 20;
public float perceptionDistance = 1.0f; public float perceptionDistance = 1.0f;
public float boundaryForce = 2.0f; public float boundaryForce = 2.0f;