From 2bae70fae26e8929c7dfa0cbb8be68be2df4fd3b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 2 Dec 2025 11:15:29 +0100 Subject: [PATCH] boundary using Avoidance Nucleus --- Assembly-CSharp.csproj | 2 + Assets/NanoBrain/Nucleus.cs | 10 +++ Assets/NanoBrain/Perception.cs | 2 +- Assets/Scenes/Boids/Boids.unity | 8 +- Assets/Scenes/Boids/Prefabs/Boid.prefab | 3 +- Assets/Scenes/Boids/Scripts/Boid.cs | 87 +++++++++---------- Assets/Scenes/Boids/Scripts/RoamingNucleus.cs | 14 +++ .../Boids/Scripts/RoamingNucleus.cs.meta | 2 + .../Scenes/Boids/Scripts/SwarmingNucleus.cs | 29 +++++++ .../Boids/Scripts/SwarmingNucleus.cs.meta | 2 + 10 files changed, 107 insertions(+), 52 deletions(-) create mode 100644 Assets/Scenes/Boids/Scripts/RoamingNucleus.cs create mode 100644 Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta create mode 100644 Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs create mode 100644 Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 526dc5f..cc63681 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -52,7 +52,9 @@ + + diff --git a/Assets/NanoBrain/Nucleus.cs b/Assets/NanoBrain/Nucleus.cs index e3a398d..e4b4a66 100644 --- a/Assets/NanoBrain/Nucleus.cs +++ b/Assets/NanoBrain/Nucleus.cs @@ -4,4 +4,14 @@ public class Nucleus { } 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); + } } \ No newline at end of file diff --git a/Assets/NanoBrain/Perception.cs b/Assets/NanoBrain/Perception.cs index b83b402..5516459 100644 --- a/Assets/NanoBrain/Perception.cs +++ b/Assets/NanoBrain/Perception.cs @@ -15,7 +15,7 @@ public class Perception : Nucleus { public HashSet positionReceivers { get; protected set; } public HashSet velocityReceivers { get; protected set; } - public Perception(NeuroidNetwork neuroidNet) { + public Perception(NeuroidNetwork neuroidNet) : base(neuroidNet) { this.neuroidNet = neuroidNet; this.positionReceivers = new(); this.velocityReceivers = new(); diff --git a/Assets/Scenes/Boids/Boids.unity b/Assets/Scenes/Boids/Boids.unity index ee7a797..e7ee4e7 100644 --- a/Assets/Scenes/Boids/Boids.unity +++ b/Assets/Scenes/Boids/Boids.unity @@ -375,7 +375,7 @@ MonoBehaviour: inertia: 0.1 alignmentForce: 5 cohesionForce: 5 - separationForce: 5 + avoidanceForce: 5 separationDistance: 0.3 perceptionDistance: 1 boundaryForce: 5 @@ -393,7 +393,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec888ca5333d45a438f9f417fa5ce135, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::SwarmSpawn - count: 2 + count: 1 boidPrefab: {fileID: 8702527964058765413, guid: f9c706268554ce449a8773675b2864b8, type: 3} spawnAreaSize: {x: 0.5, y: 0.5, z: 0.5} minDelay: 0.05 @@ -442,7 +442,7 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 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_Children: [] m_Father: {fileID: 1826482027} @@ -772,7 +772,7 @@ Transform: serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 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_Children: [] m_Father: {fileID: 1826482027} diff --git a/Assets/Scenes/Boids/Prefabs/Boid.prefab b/Assets/Scenes/Boids/Prefabs/Boid.prefab index 7f21df2..89241e9 100644 --- a/Assets/Scenes/Boids/Prefabs/Boid.prefab +++ b/Assets/Scenes/Boids/Prefabs/Boid.prefab @@ -160,12 +160,13 @@ MonoBehaviour: m_EditorClassIdentifier: speed: 0.2 neighbourCount: 0 - inertia: 0.2 + inertia: 0 alignmentForce: 1 cohesionForce: 1 separationForce: 1 separationDistance: 0.5 bodyForce: 1 + debug: 0 sc: {fileID: 0} velocity: {x: 0, y: 0, z: 0} acceleration: {x: 0, y: 0, z: 0} diff --git a/Assets/Scenes/Boids/Scripts/Boid.cs b/Assets/Scenes/Boids/Scripts/Boid.cs index f239e3e..b3326fe 100644 --- a/Assets/Scenes/Boids/Scripts/Boid.cs +++ b/Assets/Scenes/Boids/Scripts/Boid.cs @@ -2,20 +2,18 @@ using UnityEngine; public class Boid : MonoBehaviour { - public float speed = 0.2f; - public int neighbourCount = 0; - public float inertia = 0.2f; - public float alignmentForce = 1.0f; - public float cohesionForce = 1.0f; - public float separationForce = 1.0f; - public float separationDistance = 0.5f; - public float bodyForce = 1; + // public float speed = 0.2f; + // public int neighbourCount = 0; + // public float inertia = 0.2f; + // public float alignmentForce = 1.0f; + // public float cohesionForce = 1.0f; + // public float separationForce = 1.0f; + // public float separationDistance = 0.5f; + // public float bodyForce = 1; public const int BoundaryType = 1; public const int BoidType = 2; - public bool debug = false; - public SwarmControl sc; public Vector3 velocity = Vector3.zero; public Vector3 acceleration = Vector3.zero; @@ -25,16 +23,13 @@ public class Boid : MonoBehaviour { readonly Collider[] results = new Collider[10]; - //public SensoryNeuroid[] neighbourSensor = new SensoryNeuroid[6]; - public Perception perception; - public NeuroidNetwork neuroidNet = new(); - public Neuroid bodyVector; + public Perception perception; public Neuroid cohesion; public Neuroid alignment; public Neuroid avoidance; - // public Neuroid target; - public Neuroid boundary; + // public Neuroid boundary; + public Roaming roaming; public Neuroid totalForce; @@ -50,27 +45,29 @@ public class Boid : MonoBehaviour { perception = new Perception(neuroidNet); - cohesion = new(neuroidNet, "Cohesion"); - perception.SendPositions(cohesion, 1.0f, BoidType); + // 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); + // avoidance = new(neuroidNet, "Separation") { inverse = true }; + // perception.SendPositions(avoidance, sc.avoidanceForce); - boundary = new(neuroidNet, "Boundary"); + //boundary = new(neuroidNet, "Boundary"); + roaming = new(neuroidNet, perception, sc); totalForce = new(neuroidNet, "Total"); //totalForce.GetInputFrom(alignment, sc.alignmentForce); //totalForce.GetInputFrom(cohesion, sc.cohesionForce); - totalForce.GetInputFrom(avoidance, -sc.avoidanceForce); + // totalForce.GetInputFrom(avoidance, -sc.avoidanceForce); //totalForce.GetInputFrom(boundary, sc.boundaryForce); + roaming.AddReceiver(totalForce); } void Update() { - Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); + // Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results); // foreach (Collider c in results) { // if (c == null) // continue; @@ -91,28 +88,22 @@ public class Boid : MonoBehaviour { if (!innerBounds.Contains(this.transform.position)) { Vector3 point = this.transform.position; - Vector3 toBounds; - if (outerBounds.Contains(this.transform.position)) { - Vector3 pointOnBounds = ClosestPointOnBoundsSurface(outerBounds, point); - toBounds = this.transform.InverseTransformPoint(pointOnBounds); - } - else { - Vector3 pointOnBounds = innerBounds.ClosestPoint(point); - toBounds = -this.transform.InverseTransformPoint(pointOnBounds); - } - perception.ProcessStimulus(777, BoundaryType, toBounds); - } else + Vector3 pointOnBounds = innerBounds.ClosestPoint(point); + Vector3 desiredWorldSpace = (pointOnBounds - point).normalized * sc.speed; + Vector3 desiredLocalSpace = -this.transform.InverseTransformPoint(desiredWorldSpace); + perception.ProcessStimulus(777, BoundaryType, desiredLocalSpace); + } + else { 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); - this.velocity = (1 - sc.inertia) * (worldForce * Time.deltaTime) + sc.inertia * velocity + (sc.speed * transform.forward); - //this.velocity = Vector3.ClampMagnitude(this.velocity, sc.speed); + Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); + + 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; @@ -121,7 +112,6 @@ public class Boid : MonoBehaviour { 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(); } @@ -139,8 +129,13 @@ public class Boid : MonoBehaviour { void OnDrawGizmosSelected() { Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance); Gizmos.color = Color.yellow; - Gizmos.DrawRay(transform.position, this.transform.TransformDirection(totalForce.outputValue) * 10); - Gizmos.color = Color.magenta; - Gizmos.DrawRay(transform.position, this.transform.TransformDirection(avoidance.outputValue) * 10); + Vector3 worldForce = this.transform.TransformDirection(totalForce.outputValue); + Gizmos.DrawRay(transform.position, worldForce * 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); } } diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs new file mode 100644 index 0000000..aacd705 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs @@ -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); + } +} \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta new file mode 100644 index 0000000..27a0198 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/RoamingNucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2c0f5292293252943b1d45dbd1d14515 \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs new file mode 100644 index 0000000..b40f1c6 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs @@ -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); + } +} \ No newline at end of file diff --git a/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta new file mode 100644 index 0000000..f303111 --- /dev/null +++ b/Assets/Scenes/Boids/Scripts/SwarmingNucleus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 14b1bfd5a5b0784e098fc5e47b1720a1 \ No newline at end of file