diff --git a/Boids/Assets/Editor/BoidEditor.cs b/Boids/Assets/Editor/BoidEditor.cs index 6686879..97bdba6 100644 --- a/Boids/Assets/Editor/BoidEditor.cs +++ b/Boids/Assets/Editor/BoidEditor.cs @@ -1,15 +1,15 @@ using UnityEditor; using UnityEngine; -[CustomEditor(typeof(Boid))] -public class BoidEditor : UnityEditor.Editor { - public override void OnInspectorGUI() { - base.OnInspectorGUI(); - - Boid boid = (Boid) target; - GUILayout.Label($"Boid heading at ({boid._velocity.x}, {boid._velocity.y})"); - } -} +// [CustomEditor(typeof(Boid))] +// public class BoidEditor : UnityEditor.Editor { +// public override void OnInspectorGUI() { +// base.OnInspectorGUI(); +// +// Boid boid = (Boid) target; +// GUILayout.Label($"Boid heading at ({boid.velocity.x}, {boid.velocity.y})"); +// } +// } public class BoidGizmoDrawer { [DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)] @@ -17,7 +17,7 @@ public class BoidGizmoDrawer { // Simply draw the # of Boids within the perceived flock Handles.Label(boid.transform.position, $"{boid.transform.name}/{boid.latestNeighborhoodCount}"); - if(boid._isFocused) + if(boid.isFocused) foreach(Boid flockmate in boid.latestNeighborhood) Handles.DrawDottedLine(boid.transform.position, flockmate.transform.position, 1f); } diff --git a/Boids/Assets/Scripts/Boid.cs b/Boids/Assets/Scripts/Boid.cs index df8f911..75c4e27 100644 --- a/Boids/Assets/Scripts/Boid.cs +++ b/Boids/Assets/Scripts/Boid.cs @@ -1,35 +1,38 @@ -using System; -using System.Collections.Generic; - using UnityEditor; +using System.Collections.Generic; using UnityEngine; -using Random = UnityEngine.Random; -// Boids are represented by a moving, rotating triangle. -// Boids should communicate with sibling Boids via the parental BoidController object public class Boid : MonoBehaviour { - [NonSerialized] private Vector2 _position = Vector2.zero; - [NonSerialized] public Vector2 _velocity; - [NonSerialized] private bool _isWrappingX = false; - [NonSerialized] private bool _isWrappingY = false; - [NonSerialized] private Vector2 _centeringVelocity; - [NonSerialized] public int latestNeighborhoodCount = 0; - [NonSerialized] public List latestNeighborhood; - [NonSerialized] private BoidController _parent; - [NonSerialized] public bool _isFocused = false; - [NonSerialized] private LineRenderer[] _lineRenderers; + // Basic Boid Physics Attributes + private Vector2 _position = Vector2.zero; + public Vector2 velocity; + // Wrapping related attributes + private bool _isWrappingX; + private bool _isWrappingY; + private Vector2 _centeringVelocity; + + // Used for tracking Gizmo drawing + public int latestNeighborhoodCount = 0; + public List latestNeighborhood; + + // Parent Boid Controller + private BoidController _parent; + + public bool isFocused; // Whether or not the current Boid is focused + private LineRenderer[] _lineRenderers; // Store LineRenderers used by Focused Boids private void Start() { _parent = transform.parent .GetComponent(); // Parent used to perform physics math without caching - _velocity = Util.GetRandomVelocity(Random.Range(_parent.minSpeed, _parent.maxSpeed)); // Acquire a Velocity Vector with a magnitude + velocity = Util.GetRandomVelocity(Random.Range(_parent.minSpeed, + _parent.maxSpeed)); // Acquire a Velocity Vector with a magnitude _position = transform.position; // Track 2D position separately transform.name = $"Boid {transform.GetSiblingIndex()}"; // Name the Game Object so Boids can be tracked somewhat } private void Update() { // Updates the rotation of the object based on the Velocity - transform.eulerAngles = new Vector3(0, 0, Mathf.Rad2Deg * -Mathf.Atan2(_velocity.x, _velocity.y)); + transform.eulerAngles = new Vector3(0, 0, Mathf.Rad2Deg * -Mathf.Atan2(velocity.x, velocity.y)); // Skip Flock Calculations if wrapping in progress if (_isWrappingX || _isWrappingY) { @@ -44,7 +47,7 @@ public class Boid : MonoBehaviour { latestNeighborhoodCount = flock.Count; // Only update latest neighborhood when we need it for focused boid Gizmo draws - if (_isFocused) + if (isFocused) latestNeighborhood = flock; // Calculate all offsets and multiple by magnitudes given @@ -62,13 +65,13 @@ public class Boid : MonoBehaviour { } // Limit the Velocity Vector to a certain Magnitude - _velocity += acceleration * Time.deltaTime; - float speed = _velocity.magnitude; - Vector2 dir = _velocity / speed; + velocity += acceleration * Time.deltaTime; + float speed = velocity.magnitude; + Vector2 dir = velocity / speed; speed = Mathf.Clamp(speed, _parent.minSpeed, _parent.maxSpeed); - _velocity = dir * speed; + velocity = dir * speed; - _position += _velocity * Time.deltaTime; + _position += velocity * Time.deltaTime; transform.position = _position; // transform.forward = dir; } @@ -83,7 +86,7 @@ public class Boid : MonoBehaviour { /// Force Vector being applied by a rule /// Vector2 force to be applied private Vector2 SteerTowards(Vector2 vector) { - Vector2 v = vector.normalized * _parent.maxSpeed - _velocity; + Vector2 v = vector.normalized * _parent.maxSpeed - velocity; return Vector2.ClampMagnitude(v, _parent.maxSteerForce); } @@ -150,9 +153,9 @@ public class Boid : MonoBehaviour { Vector2 perceived = Vector2.zero; foreach (Boid boid in flock) - perceived += boid._velocity; + perceived += boid.velocity; perceived /= flock.Count; - return (perceived - _velocity) / 8.0f; + return (perceived - velocity) / 8.0f; } // Asks Boids to stay within the Boundaries set @@ -189,15 +192,15 @@ public class Boid : MonoBehaviour { // FOV Check if (_parent.enableFovChecks) { - float angle1 = Util.Vector2ToAngle(_velocity); // Current Heading - float angle2 = Util.AngleBetween(transform.position, boid.transform.position); // Angle between Boid and other Boid + float angle1 = Util.Vector2ToAngle(velocity); // Current Heading + float angle2 = + Util.AngleBetween(transform.position, boid.transform.position); // Angle between Boid and other Boid // Outside of FOV range, skip if (Mathf.Abs(Mathf.DeltaAngle(angle1, angle2)) > _parent.boidFov / 2) continue; - } - + // Boid passed all checks, add to local Flock list flock.Add(boid); } @@ -207,12 +210,12 @@ public class Boid : MonoBehaviour { // Sets up a Boid to be 'Focused', adds Circles around object and changes color public void EnableFocusing() { - if (_isFocused) { + if (isFocused) { Debug.LogWarning($"enableFocusing called on previously focused Boid ({transform.name})"); return; } - _isFocused = true; + isFocused = true; // Create all LineRenderers _lineRenderers = new LineRenderer[3]; @@ -230,13 +233,13 @@ public class Boid : MonoBehaviour { // Disable focusing, removing LineRenderers and resetting color public void DisableFocusing() { - _isFocused = false; + isFocused = false; // Update Mesh Material Color var oldTriangle = transform.GetComponent(); oldTriangle.meshRenderer.material.color = new Color32(49, 61, 178, 255); - - + + // Destroy Line Renderers (and child GameObjects) for (int i = 0; i < _lineRenderers.Length; i++) { _lineRenderers[i].positionCount = 0; @@ -265,12 +268,12 @@ public class Boid : MonoBehaviour { /// true if draw operation should be treated as a re-draw public void Draw(bool redraw) { // Clear positions when redrawing - if(redraw) + if (redraw) foreach (LineRenderer lineRenderer in _lineRenderers) lineRenderer.positionCount = 0; - + // Add a LineRenderer for Radius Drawing - if(_parent.enableFovChecks) + if (_parent.enableFovChecks) ShapeDraw.DrawArc(_lineRenderers[2], _parent.boidFov, _parent.boidGroupRange); // FOV Arc else ShapeDraw.DrawCircle(_lineRenderers[0], _parent.boidGroupRange); // Group Circle diff --git a/Boids/Assets/Scripts/BoidController.cs b/Boids/Assets/Scripts/BoidController.cs index 28f3be9..883c3b0 100644 --- a/Boids/Assets/Scripts/BoidController.cs +++ b/Boids/Assets/Scripts/BoidController.cs @@ -6,42 +6,43 @@ using Debug = System.Diagnostics.Debug; using Random = UnityEngine.Random; public class BoidController : MonoBehaviour { - // Controller Attributes - [NonSerialized] public Rect Space; - [NonSerialized] public Rect Boundary; + // Manually managed/set + public GameObject boidObject; // Boid Object Prefab + // Swarm Attributes - [SerializeField] public int boidCount = 250; - [SerializeField] public float boidGroupRange = 3.3f; - [SerializeField] public float minSpeed; - [SerializeField] public float maxSpeed; + public int boidCount = 250; + public float boidGroupRange = 3.3f; + public float minSpeed; + public float maxSpeed; // Boid Rules are multiplied by this to allow rule 'tweaking' - [SerializeField] public float globalBias = 1.0f; - [SerializeField] public float separationBias = 2f; - [SerializeField] public float alignmentBias = 0.288f; - [SerializeField] public float cohesionBias = 0.3f; - [SerializeField] public float boundaryBias = 1.5f; + public float globalBias = 1.0f; + public float separationBias = 2f; + public float alignmentBias = 0.288f; + public float cohesionBias = 0.3f; + public float boundaryBias = 1.5f; // Enable/Disable Boid Rules Altogether - [SerializeField] public bool enableSeparation = true; - [SerializeField] public bool enableAlignment = true; - [SerializeField] public bool enableCohesion = true; - [SerializeField] public bool enableBoundary = true; - [SerializeField] public bool enableFovChecks = true; + public bool enableSeparation = true; + public bool enableAlignment = true; + public bool enableCohesion = true; + public bool enableBoundary = true; + public bool enableFovChecks = true; - [SerializeField] public float boidSeparationRange = 1.4f; // Boid Separation rule's activation distance - [SerializeField] public float boundaryForce = 50f; // The force applied when a Boid hits the boundary - [SerializeField] public bool localFlocks = true; // Calculate Local 'Neighborhood' for flocks? - [SerializeField] public bool edgeWrapping = true; // Enforce Edge Wrapping - [SerializeField] public float maxSteerForce = 400f; - [SerializeField] public float boidFov = 240; + public float boidSeparationRange = 1.4f; // Boid Separation rule's activation distance + public float boundaryForce = 50f; // The force applied when a Boid hits the boundary + public bool localFlocks = true; // Calculate Local 'Neighborhood' for flocks? + public bool edgeWrapping = true; // Enforce Edge Wrapping + public float maxSteerForce = 400f; + public float boidFov = 240; - - public Boid focusedBoid; // A focused Boid has special rendering - public GameObject boidObject; // Boid Object Prefab + // Runtime Controller Attributes [NonSerialized] public List boids = new List(); // Boid Objects for Updates + [NonSerialized] public Rect Space; + [NonSerialized] public Rect Boundary; [NonSerialized] public Camera Cam; // Used for wrapping detection + public Boid focusedBoid; // A focused Boid has special rendering private void OnDrawGizmos() { // Draw a Wire Cube for the Rectangle Area