diff --git a/Boids/Assets/Editor/BoidControllerEditor.cs b/Boids/Assets/Editor/BoidControllerEditor.cs index 460995e..1468abf 100644 --- a/Boids/Assets/Editor/BoidControllerEditor.cs +++ b/Boids/Assets/Editor/BoidControllerEditor.cs @@ -64,5 +64,7 @@ public class BoidControllerEditor : UnityEditor.Editor { // Inspector elements related to Boid Focusing have changed - redraw! if (redraw && controller.focusedBoid != null) controller.focusedBoid.Draw(true); + + Time.timeScale = EditorGUILayout.Slider("Time Scale", Time.timeScale, 0.02f, 1f); } } \ No newline at end of file diff --git a/Boids/Assets/Scripts/AdjustmentsHandler.cs b/Boids/Assets/Scripts/AdjustmentsHandler.cs index 12026b8..ba8bf17 100644 --- a/Boids/Assets/Scripts/AdjustmentsHandler.cs +++ b/Boids/Assets/Scripts/AdjustmentsHandler.cs @@ -81,7 +81,7 @@ public class AdjustmentsHandler : MonoBehaviour { // Calculate diff, formally add/remove boids int diff = controller.boidCount - controller.boids.Count; if(diff > 0) - controller.AddBoids(diff); + controller.AddBoids(diff, controller.boidCount > 5); else if(diff < 0) controller.RemoveBoids(diff * -1); diff --git a/Boids/Assets/Scripts/Boid.cs b/Boids/Assets/Scripts/Boid.cs index fbe5136..23e67a5 100644 --- a/Boids/Assets/Scripts/Boid.cs +++ b/Boids/Assets/Scripts/Boid.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using UnityEngine; public class Boid : MonoBehaviour { @@ -24,8 +25,7 @@ public class Boid : MonoBehaviour { 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)); _position = transform.position; // Track 2D position separately transform.name = $"Boid {transform.GetSiblingIndex()}"; // Name the Game Object so Boids can be tracked somewhat } @@ -41,45 +41,58 @@ public class Boid : MonoBehaviour { transform.position = _position; } else { - // Find local neighborhood flock - Vector2 acceleration = Vector2.zero; - List flock = _parent.localFlocks ? GetFlock(_parent.boids, _parent.boidGroupRange) : _parent.boids; - latestNeighborhoodCount = flock.Count; - - // Only update latest neighborhood when we need it for focused boid Gizmo draws - if (isFocused) - latestNeighborhood = flock; - - // Calculate all offsets and multiple by magnitudes given - if (flock.Count > 0) { - if (_parent.enableCohesion) - acceleration += SteerTowards(Rule1(flock)) * _parent.cohesionBias; - if (_parent.enableSeparation) - acceleration += SteerTowards(Rule2(flock)) * _parent.separationBias; - if (_parent.enableAlignment) - acceleration += SteerTowards(Rule3(flock)) * _parent.alignmentBias; - } - - if (_parent.enableBoundary && !_parent.Boundary.Contains(_position)) { - acceleration += SteerTowards(RuleBound()) * _parent.boundaryBias; - } - - // Limit the Velocity Vector to a certain Magnitude - velocity += acceleration * Time.deltaTime; - float speed = velocity.magnitude; - Vector2 dir = velocity / speed; - speed = Mathf.Clamp(speed, _parent.minSpeed, _parent.maxSpeed); - velocity = dir * speed; - + velocity = GetVelocity(); _position += velocity * Time.deltaTime; transform.position = _position; - // transform.forward = dir; } + // Perform edge wrapping if (_parent.edgeWrapping) Wrapping(); } + /// + /// Gets Velocity used to move Boid with all current rules and velocity + /// + /// new current Vector2 velocity + public Vector2 GetVelocity() { + // Find local neighborhood flock + Vector2 acceleration = Vector2.zero; + List flock; + + if (_parent.localFlocks) + flock = GetFlock(_parent.boids, _parent.boidGroupRange); + else + flock = _parent.boids; + + latestNeighborhoodCount = flock.Count; + + // Only update latest neighborhood when we need it for focused boid Gizmo draws + if (isFocused) + latestNeighborhood = flock; + + // Calculate all offsets and multiple by magnitudes given + if (flock.Count > 0) { + if (_parent.enableCohesion) + acceleration += SteerTowards(Rule1(flock)) * _parent.cohesionBias; + if (_parent.enableSeparation) + acceleration += SteerTowards(Rule2(flock)) * _parent.separationBias; + if (_parent.enableAlignment) + acceleration += SteerTowards(Rule3(flock)) * _parent.alignmentBias; + } + + if (_parent.enableBoundary && !_parent.Boundary.Contains(_position)) { + acceleration += SteerTowards(RuleBound()) * _parent.boundaryBias; + } + + // Limit the Velocity Vector to a certain Magnitude + Vector2 newVelocity = velocity + acceleration * Time.deltaTime; + float speed = newVelocity.magnitude; + Vector2 dir = newVelocity / speed; + speed = Mathf.Clamp(speed, _parent.minSpeed, _parent.maxSpeed); + return dir * speed; + } + /// /// Assists with clamping and normalizing a Vector2 force /// @@ -90,6 +103,9 @@ public class Boid : MonoBehaviour { return Vector2.ClampMagnitude(v, _parent.maxSteerForce); } + /// + /// Runs edge wrapping logic for detecting and wrapping Boids + /// private void Wrapping() { if (!_parent.Space.Contains(_position)) { // Activate Wrap, Move @@ -295,4 +311,26 @@ public class Boid : MonoBehaviour { return _position + Util.RotateBy(new Vector2(distance, distance), Random.Range(0f, 360f)); } + + public Boid GetClosestBoid() { + if (_parent.boids.Count <= 1) + return null; + + Boid best = _parent.boids[0]; + float curDistSqr = Mathf.Infinity; + + foreach (Boid potential in _parent.boids) { + if (potential == this) + continue; + + Vector2 diff = potential._position - _position; + var diffSqrMag = diff.sqrMagnitude; + if (diffSqrMag < curDistSqr) { + curDistSqr = diffSqrMag; + best = potential; + } + } + + return best; + } } \ No newline at end of file diff --git a/Boids/Assets/Scripts/BoidController.cs b/Boids/Assets/Scripts/BoidController.cs index 1f3bf65..b5bbee8 100644 --- a/Boids/Assets/Scripts/BoidController.cs +++ b/Boids/Assets/Scripts/BoidController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; @@ -82,6 +83,17 @@ public class BoidController : MonoBehaviour { private void Start() { SetupCamera(); AddBoids(boidCount); + + StartCoroutine(LateStart()); + } + + private IEnumerator LateStart() { + yield return new WaitForSecondsRealtime(0.5f); + + for (int i = 0; i < 100; i++) { + foreach (Boid boid in boids) + boid.velocity = boid.GetVelocity(); + } } /// @@ -115,11 +127,13 @@ public class BoidController : MonoBehaviour { for (int i = 0; i < n; i++) { // Instantiate a Boid prefab within the boundaries randomly Vector2 position = useNearby ? RandomNearbyPosition() : RandomPosition() * 0.90f; - GameObject boid = Instantiate(boidObject, position, Quaternion.identity); + GameObject boidGO = Instantiate(boidObject, position, Quaternion.identity); // Set parent, add Boid component to Boids list - boid.transform.parent = transform; - boids.Add(boid.GetComponent()); + boidGO.transform.parent = transform; + var boid = boidGO.GetComponent(); + + boids.Add(boid); } }