boundary using Avoidance Nucleus

This commit is contained in:
Pascal Serrarens 2025-12-02 11:15:29 +01:00
parent bb5939b6ab
commit 2bae70fae2
10 changed files with 107 additions and 52 deletions

View File

@ -52,7 +52,9 @@
<Compile Include="Assets/NanoBrain/NeuroidBehaviour.cs" /> <Compile Include="Assets/NanoBrain/NeuroidBehaviour.cs" />
<Compile Include="Assets/NanoBrain/SensoryNeuroid.cs" /> <Compile Include="Assets/NanoBrain/SensoryNeuroid.cs" />
<Compile Include="Assets/Scenes/Boids/Scripts/SwarmControl.cs" /> <Compile Include="Assets/Scenes/Boids/Scripts/SwarmControl.cs" />
<Compile Include="Assets/Scenes/Boids/Scripts/RoamingNucleus.cs" />
<Compile Include="Assets/NanoBrain/Perception.cs" /> <Compile Include="Assets/NanoBrain/Perception.cs" />
<Compile Include="Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs" />
<Compile Include="Assets/Scenes/Boids/Scripts/Boid.cs" /> <Compile Include="Assets/Scenes/Boids/Scripts/Boid.cs" />
<Compile Include="Assets/NanoBrain/Neuroid.cs" /> <Compile Include="Assets/NanoBrain/Neuroid.cs" />
<Compile Include="Assets/NanoBrain/Nucleus.cs" /> <Compile Include="Assets/NanoBrain/Nucleus.cs" />

View File

@ -4,4 +4,14 @@ public class Nucleus {
} }
public State state; public State state;
public Neuroid output;
public Nucleus(NeuroidNetwork neuroidNet) {
this.output = new(neuroidNet, "Nucleus output");
}
public void AddReceiver(Neuroid receiver) {
this.output.AddReceiver(receiver);
}
} }

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) { public Perception(NeuroidNetwork neuroidNet) : base(neuroidNet) {
this.neuroidNet = neuroidNet; this.neuroidNet = neuroidNet;
this.positionReceivers = new(); this.positionReceivers = new();
this.velocityReceivers = new(); this.velocityReceivers = new();

View File

@ -375,7 +375,7 @@ MonoBehaviour:
inertia: 0.1 inertia: 0.1
alignmentForce: 5 alignmentForce: 5
cohesionForce: 5 cohesionForce: 5
separationForce: 5 avoidanceForce: 5
separationDistance: 0.3 separationDistance: 0.3
perceptionDistance: 1 perceptionDistance: 1
boundaryForce: 5 boundaryForce: 5
@ -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: 2 count: 1
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
@ -442,7 +442,7 @@ Transform:
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 10, z: 0} m_LocalPosition: {x: 0, y: 10, z: 0}
m_LocalScale: {x: 10, y: 1, z: 10} m_LocalScale: {x: 10, y: 0.1, z: 10}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 1826482027} m_Father: {fileID: 1826482027}
@ -772,7 +772,7 @@ Transform:
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 10, y: 1, z: 10} m_LocalScale: {x: 10, y: 0.1, z: 10}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 1826482027} m_Father: {fileID: 1826482027}

View File

@ -160,12 +160,13 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
speed: 0.2 speed: 0.2
neighbourCount: 0 neighbourCount: 0
inertia: 0.2 inertia: 0
alignmentForce: 1 alignmentForce: 1
cohesionForce: 1 cohesionForce: 1
separationForce: 1 separationForce: 1
separationDistance: 0.5 separationDistance: 0.5
bodyForce: 1 bodyForce: 1
debug: 0
sc: {fileID: 0} sc: {fileID: 0}
velocity: {x: 0, y: 0, z: 0} velocity: {x: 0, y: 0, z: 0}
acceleration: {x: 0, y: 0, z: 0} acceleration: {x: 0, y: 0, z: 0}

View File

@ -2,20 +2,18 @@ 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;
public float alignmentForce = 1.0f; // public float alignmentForce = 1.0f;
public float cohesionForce = 1.0f; // public float cohesionForce = 1.0f;
public float separationForce = 1.0f; // public float separationForce = 1.0f;
public float separationDistance = 0.5f; // public float separationDistance = 0.5f;
public float bodyForce = 1; // public float bodyForce = 1;
public const int BoundaryType = 1; public const int BoundaryType = 1;
public const int BoidType = 2; public const int BoidType = 2;
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;
@ -25,16 +23,13 @@ public class Boid : MonoBehaviour {
readonly Collider[] results = new Collider[10]; readonly Collider[] results = new Collider[10];
//public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6];
public Perception perception;
public NeuroidNetwork neuroidNet = new(); public NeuroidNetwork neuroidNet = new();
public Neuroid bodyVector; public Perception perception;
public Neuroid cohesion; public Neuroid cohesion;
public Neuroid alignment; public Neuroid alignment;
public Neuroid avoidance; public Neuroid avoidance;
// public Neuroid target; // public Neuroid boundary;
public Neuroid boundary; public Roaming roaming;
public Neuroid totalForce; public Neuroid totalForce;
@ -50,27 +45,29 @@ public class Boid : MonoBehaviour {
perception = new Perception(neuroidNet); perception = new Perception(neuroidNet);
cohesion = new(neuroidNet, "Cohesion"); // cohesion = new(neuroidNet, "Cohesion");
perception.SendPositions(cohesion, 1.0f, BoidType); // perception.SendPositions(cohesion, 1.0f, BoidType);
// alignment = new(neuroidNet, "Alignment") { average = true }; // alignment = new(neuroidNet, "Alignment") { average = true };
// perception.SendVelocities(alignment); // perception.SendVelocities(alignment);
avoidance = new(neuroidNet, "Separation") { inverse = true }; // avoidance = new(neuroidNet, "Separation") { inverse = true };
perception.SendPositions(avoidance, sc.avoidanceForce); // perception.SendPositions(avoidance, sc.avoidanceForce);
boundary = new(neuroidNet, "Boundary"); //boundary = new(neuroidNet, "Boundary");
roaming = new(neuroidNet, perception, sc);
totalForce = new(neuroidNet, "Total"); 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(avoidance, -sc.avoidanceForce); // totalForce.GetInputFrom(avoidance, -sc.avoidanceForce);
//totalForce.GetInputFrom(boundary, sc.boundaryForce); //totalForce.GetInputFrom(boundary, sc.boundaryForce);
roaming.AddReceiver(totalForce);
} }
void Update() { void Update() {
Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); // Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results);
// foreach (Collider c in results) { // foreach (Collider c in results) {
// if (c == null) // if (c == null)
// continue; // continue;
@ -91,28 +88,22 @@ public class Boid : MonoBehaviour {
if (!innerBounds.Contains(this.transform.position)) { if (!innerBounds.Contains(this.transform.position)) {
Vector3 point = this.transform.position; Vector3 point = this.transform.position;
Vector3 toBounds; Vector3 pointOnBounds = innerBounds.ClosestPoint(point);
if (outerBounds.Contains(this.transform.position)) { Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed;
Vector3 pointOnBounds = ClosestPointOnBoundsSurface(outerBounds, point); Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace);
toBounds = this.transform.InverseTransformPoint(pointOnBounds); perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace);
} }
else { else {
Vector3 pointOnBounds = innerBounds.ClosestPoint(point);
toBounds = -this.transform.InverseTransformPoint(pointOnBounds);
}
perception.ProcessStimulus(777, BoundaryType, toBounds);
} else
perception.RemoveStimulus(777); perception.RemoveStimulus(777);
Vector3 totalForceVector = totalForce.outputValue;
if (this.debug) {
Debug.Log($"Cohesion {cohesion.outputValue.magnitude} separation {avoidance.outputValue.magnitude} alignment {alignment.outputValue.magnitude}");
} }
Vector3 worldForce = this.transform.TransformDirection(totalForceVector); Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue);
this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward);
//this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed); this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity;
if (this.velocity.magnitude > 0)
this.velocity = this.velocity.normalized * sc.speed;
else
this.velocity = this.transform.forward * sc.speed;
this.transform.position += this.velocity * Time.deltaTime; this.transform.position += this.velocity * Time.deltaTime;
@ -121,7 +112,6 @@ public class Boid : MonoBehaviour {
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
} }
//Debug.Log($"neighbours: {neighbourCount} synapses: {cohesion.synapses.Count}");
neuroidNet.Update(); neuroidNet.Update();
} }
@ -139,8 +129,13 @@ public class Boid : MonoBehaviour {
void OnDrawGizmosSelected() { void OnDrawGizmosSelected() {
Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance);
Gizmos.color = Color.yellow; Gizmos.color = Color.yellow;
Gizmos.DrawRay(transform.position, this.transform.TransformDirection(totalForce.outputValue) * 10); Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue);
Gizmos.color = Color.magenta; Gizmos.DrawRay(transform.position, worldForce * 10);
Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); // Gizmos.color = Color.magenta;
// Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10);
// Debug.Log($"Avoidance {roaming.avoidance.outputValue} Roaming {roaming.output.outputValue} Total {totalForce.outputValue}");
// Debug.Log($"WorldForce {worldForce} velocity {velocity} inertia {sc.inertia}");
Gizmos.color = Color.blue;
Gizmos.DrawRay(transform.position, this.velocity * 10);
} }
} }

View File

@ -0,0 +1,14 @@
public class Roaming : Nucleus {
public Neuroid avoidance;
public const int BoundaryType = 1;
public const int BoidType = 2;
public Roaming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) {
avoidance = new(neuroidNet, "Separation") { inverse = true };
perception.SendPositions(avoidance);
output.GetInputFrom(avoidance, -sc.avoidanceForce);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2c0f5292293252943b1d45dbd1d14515

View File

@ -0,0 +1,29 @@
public class Swarming : Nucleus {
//public Perception perception;
public Neuroid cohesion;
public Neuroid alignment;
public Neuroid avoidance;
public Neuroid boundary;
public const int BoundaryType = 1;
public const int BoidType = 2;
public Swarming(NeuroidNetwork neuroidNet, Perception perception, SwarmControl sc) : base(neuroidNet) {
cohesion = new(neuroidNet, "Cohesion");
perception.SendPositions(cohesion, 1.0f, BoidType);
alignment = new(neuroidNet, "Alignment") { average = true };
perception.SendVelocities(alignment);
avoidance = new(neuroidNet, "Separation") { inverse = true };
perception.SendPositions(avoidance, sc.avoidanceForce);
boundary = new(neuroidNet, "Boundary");
output.GetInputFrom(alignment, sc.alignmentForce);
output.GetInputFrom(cohesion, sc.cohesionForce);
output.GetInputFrom(avoidance, -sc.avoidanceForce);
output.GetInputFrom(boundary, sc.boundaryForce);
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 14b1bfd5a5b0784e098fc5e47b1720a1