114 lines
4.2 KiB
C#

using UnityEngine;
[RequireComponent(typeof(NanoBrain))]
public class Boid : MonoBehaviour {
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;
//public NeuroidNetwork neuroidNet = new();
public NanoBrain neuroidNet;
public Perception perception;
public Nucleus behaviour;
public Neuroid totalForce;
public int id;
void Awake() {
neuroidNet = GetComponent<NanoBrain>();
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);
//behaviour = new Roaming(neuroidNet, perception, sc);
behaviour = new Swarming(neuroidNet, perception, sc);
totalForce = new(neuroidNet, "Total");
behaviour.AddReceiver(totalForce);
}
void Update() {
Collider[] results = Physics.OverlapSphere(this.transform.position, sc.perceptionDistance);
foreach (Collider c in results) {
if (c as CapsuleCollider != null) {
Boid neighbour = c.GetComponentInParent<Boid>();
if (neighbour == null || neighbour == this)
continue;
Vector3 localPosition = neighbour.transform.position - this.transform.position;
int thingId = neighbour.GetInstanceID();
perception.ProcessStimulus(thingId, BoidType, localPosition); //, neighbour.gameObject.name);
}
}
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, "Boundary");
}
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() {
if (sc == null)
return;
Gizmos.DrawWireSphere(this.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);
}
}