142 lines
5.3 KiB
C#
142 lines
5.3 KiB
C#
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 const int BoundaryType = 1;
|
|
public const int BoidType = 2;
|
|
|
|
public SwarmControl sc;
|
|
public Vector3 velocity = Vector3.zero;
|
|
public Vector3 acceleration = Vector3.zero;
|
|
|
|
private Bounds innerBounds;
|
|
private Bounds outerBounds;
|
|
|
|
readonly Collider[] results = new Collider[10];
|
|
|
|
public NeuroidNetwork neuroidNet = new();
|
|
public Perception perception;
|
|
public Neuroid cohesion;
|
|
public Neuroid alignment;
|
|
public Neuroid avoidance;
|
|
// public Neuroid boundary;
|
|
public Roaming roaming;
|
|
|
|
public Neuroid totalForce;
|
|
|
|
public int id;
|
|
|
|
void Awake() {
|
|
this.id = this.GetInstanceID();
|
|
|
|
sc = FindFirstObjectByType<SwarmControl>();
|
|
|
|
innerBounds = new(sc.transform.position, sc.spaceSize - 2 * sc.boundaryWidth);
|
|
outerBounds = new(sc.transform.position, sc.spaceSize);
|
|
|
|
perception = new Perception(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");
|
|
|
|
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(boundary, sc.boundaryForce);
|
|
roaming.AddReceiver(totalForce);
|
|
}
|
|
|
|
void Update() {
|
|
// Physics.OverlapSphereNonAlloc(this.transform.position, sc.perceptionDistance, results);
|
|
// foreach (Collider c in results) {
|
|
// if (c == null)
|
|
// continue;
|
|
|
|
// if (c as CapsuleCollider != null) {
|
|
// Boid neighbour = c.GetComponentInParent<Boid>();
|
|
// if (neighbour == null || neighbour == this)
|
|
// continue;
|
|
|
|
// Vector3 localPosition = neighbour.transform.position - this.transform.position;
|
|
// if (debug)
|
|
// Debug.Log($" distance {localPosition.magnitude}");
|
|
|
|
// int thingId = neighbour.GetInstanceID();
|
|
// perception.ProcessStimulus(thingId, localPosition);
|
|
// }
|
|
// }
|
|
|
|
if (!innerBounds.Contains(this.transform.position)) {
|
|
Vector3 point = this.transform.position;
|
|
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 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;
|
|
|
|
if (this.velocity != Vector3.zero) {
|
|
Quaternion targetRotation = Quaternion.LookRotation(this.velocity);
|
|
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f); // Adjust the speed of rotation
|
|
}
|
|
|
|
neuroidNet.Update();
|
|
}
|
|
|
|
Vector3 ClosestPointOnBoundsSurface(Bounds b, Vector3 p) {
|
|
if (!b.Contains(p)) return b.ClosestPoint(p);
|
|
Vector3 d = p - b.center;
|
|
Vector3 ext = b.extents;
|
|
float sx = ext.x / Mathf.Abs(d.x);
|
|
float sy = ext.y / Mathf.Abs(d.y);
|
|
float sz = ext.z / Mathf.Abs(d.z);
|
|
float m = Mathf.Min(sx, Mathf.Min(sy, sz));
|
|
return b.center + d * m;
|
|
}
|
|
|
|
void OnDrawGizmosSelected() {
|
|
Gizmos.DrawWireSphere(transform.position, sc.perceptionDistance);
|
|
Gizmos.color = Color.yellow;
|
|
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);
|
|
}
|
|
}
|