mirror of
https://github.com/Xevion/Boids.git
synced 2025-12-17 06:11:14 -06:00
rename fov vars, add documentation & better comements to BoidController class, fix BoidControllerEditor redraw and implement circle/arc vertex/width attributes (no serialization with static class)
This commit is contained in:
@@ -9,7 +9,7 @@ public class BoidControllerEditor : UnityEditor.Editor {
|
|||||||
|
|
||||||
// Boid Count update
|
// Boid Count update
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
controller.boidCount = EditorGUILayout.IntSlider("Boid Count", controller.boidCount, 1, 500);
|
controller.boidCount = EditorGUILayout.IntSlider("Boid Count", controller.boidCount, -1, 500);
|
||||||
// Check must be performed or Boids will be added outside of gameplay
|
// Check must be performed or Boids will be added outside of gameplay
|
||||||
if (EditorGUI.EndChangeCheck() && Application.isPlaying) {
|
if (EditorGUI.EndChangeCheck() && Application.isPlaying) {
|
||||||
int diff = controller.boidCount - controller.boids.Count;
|
int diff = controller.boidCount - controller.boids.Count;
|
||||||
@@ -32,7 +32,7 @@ public class BoidControllerEditor : UnityEditor.Editor {
|
|||||||
controller.boidGroupRange = EditorGUILayout.Slider("Group Range", controller.boidGroupRange, 0.01f, 7.5f);
|
controller.boidGroupRange = EditorGUILayout.Slider("Group Range", controller.boidGroupRange, 0.01f, 7.5f);
|
||||||
controller.boidSeparationRange =
|
controller.boidSeparationRange =
|
||||||
EditorGUILayout.Slider("Separation Range", controller.boidSeparationRange, 0.01f, 5.0f);
|
EditorGUILayout.Slider("Separation Range", controller.boidSeparationRange, 0.01f, 5.0f);
|
||||||
controller.boidFOV = EditorGUILayout.Slider("Boid FOV", controller.boidFOV, 1f, 360f);
|
controller.boidFov = EditorGUILayout.Slider("Boid FOV", controller.boidFov, 1f, 360f);
|
||||||
redraw = redraw || EditorGUI.EndChangeCheck();
|
redraw = redraw || EditorGUI.EndChangeCheck();
|
||||||
|
|
||||||
// Boid Bias Attributes
|
// Boid Bias Attributes
|
||||||
@@ -47,20 +47,24 @@ public class BoidControllerEditor : UnityEditor.Editor {
|
|||||||
controller.enableAlignment = EditorGUILayout.Toggle("Enable Alignment?", controller.enableAlignment);
|
controller.enableAlignment = EditorGUILayout.Toggle("Enable Alignment?", controller.enableAlignment);
|
||||||
controller.enableCohesion = EditorGUILayout.Toggle("Enable Cohesion?", controller.enableCohesion);
|
controller.enableCohesion = EditorGUILayout.Toggle("Enable Cohesion?", controller.enableCohesion);
|
||||||
controller.enableSeparation = EditorGUILayout.Toggle("Enable Separation?", controller.enableSeparation);
|
controller.enableSeparation = EditorGUILayout.Toggle("Enable Separation?", controller.enableSeparation);
|
||||||
controller.enableBoundary = EditorGUILayout.Toggle("Enable Boundary?", controller.enableBoundary);
|
|
||||||
controller.enableFOVChecks = EditorGUILayout.Toggle("Enable FOV?", controller.enableFOVChecks);
|
|
||||||
|
|
||||||
// Boid Rendering
|
// Relevant to Focused Boid Rendering
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
controller.circleVertexCount =
|
controller.enableFovChecks = EditorGUILayout.Toggle("Enable FOV?", controller.enableFovChecks);
|
||||||
EditorGUILayout.IntSlider("Circle Vertex Count", controller.circleVertexCount, 4, 360);
|
redraw = redraw || EditorGUI.EndChangeCheck();
|
||||||
// controller.arcVertexCount =
|
|
||||||
// EditorGUILayout.IntSlider("Arc Vertex Count", controller.arcVertexCount, -1, 360);
|
controller.enableBoundary = EditorGUILayout.Toggle("Enable Boundary?", controller.enableBoundary);
|
||||||
controller.circleWidth = EditorGUILayout.Slider("Circle Line Width", controller.circleWidth, 0.01f, 1f);
|
|
||||||
|
// Focused Boid Rendering Attributes
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
ShapeDraw.CircleVertexCount = EditorGUILayout.IntSlider("Circle Vertex Count", ShapeDraw.CircleVertexCount, 4, 360);
|
||||||
|
ShapeDraw.ArcVertexCount = EditorGUILayout.IntSlider("Arc Vertex Count", ShapeDraw.ArcVertexCount + 2, 3, 360) - 2;
|
||||||
|
ShapeDraw.CircleWidth = EditorGUILayout.Slider("Circle Line Width", ShapeDraw.CircleWidth, 0.01f, 1f);
|
||||||
|
ShapeDraw.ArcWidth = EditorGUILayout.Slider("Arc Line Width", ShapeDraw.ArcWidth, 0.01f, 1f);
|
||||||
redraw = redraw || EditorGUI.EndChangeCheck();
|
redraw = redraw || EditorGUI.EndChangeCheck();
|
||||||
|
|
||||||
// Inspector elements related to Boid Focusing have changed - redraw!
|
// Inspector elements related to Boid Focusing have changed - redraw!
|
||||||
if (redraw)
|
if (redraw && controller.focusedBoid != null)
|
||||||
controller.focusedBoid.Draw(true);
|
controller.focusedBoid.Draw(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,12 +180,12 @@ public class Boid : MonoBehaviour {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// FOV Check
|
// FOV Check
|
||||||
if (_parent.enableFOVChecks) {
|
if (_parent.enableFovChecks) {
|
||||||
float angle1 = Util.Vector2ToAngle(_velocity); // Current Heading
|
float angle1 = Util.Vector2ToAngle(_velocity); // Current Heading
|
||||||
float angle2 = Util.AngleBetween(transform.position, boid.transform.position); // Angle between Boid and other Boid
|
float angle2 = Util.AngleBetween(transform.position, boid.transform.position); // Angle between Boid and other Boid
|
||||||
|
|
||||||
// Outside of FOV range, skip
|
// Outside of FOV range, skip
|
||||||
if (Mathf.Abs(Mathf.DeltaAngle(angle1, angle2)) > _parent.boidFOV / 2)
|
if (Mathf.Abs(Mathf.DeltaAngle(angle1, angle2)) > _parent.boidFov / 2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -258,16 +258,16 @@ public class Boid : MonoBehaviour {
|
|||||||
lineRenderer.positionCount = 0;
|
lineRenderer.positionCount = 0;
|
||||||
|
|
||||||
// Add a LineRenderer for Radius Drawing
|
// Add a LineRenderer for Radius Drawing
|
||||||
if(_parent.enableFOVChecks)
|
if(_parent.enableFovChecks)
|
||||||
ShapeDraw.DrawArc(_lineRenderers[2], _parent.boidFOV, _parent.boidGroupRange); // FOV Arc
|
ShapeDraw.DrawArc(_lineRenderers[2], _parent.boidFov, _parent.boidGroupRange); // FOV Arc
|
||||||
else
|
else
|
||||||
ShapeDraw.DrawCircle(_lineRenderers[0], _parent.boidGroupRange); // Group Circle
|
ShapeDraw.DrawCircle(_lineRenderers[0], _parent.boidGroupRange); // Group Circle
|
||||||
ShapeDraw.DrawCircle(_lineRenderers[1], _parent.boidSeparationRange); // Separation Circle
|
ShapeDraw.DrawCircle(_lineRenderers[1], _parent.boidSeparationRange); // Separation Circle
|
||||||
|
|
||||||
if (_parent.enableFOVChecks) {
|
if (_parent.enableFovChecks) {
|
||||||
// Set FOV Arc rotation to mimic Boid transform rotation
|
// Set FOV Arc rotation to mimic Boid transform rotation
|
||||||
_lineRenderers[2].transform.rotation = transform.rotation;
|
_lineRenderers[2].transform.rotation = transform.rotation;
|
||||||
_lineRenderers[2].transform.Rotate(0, 0, _parent.boidFOV / 2f);
|
_lineRenderers[2].transform.Rotate(0, 0, _parent.boidFov / 2f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Debug = System.Diagnostics.Debug;
|
||||||
using Random = UnityEngine.Random;
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
public class BoidController : MonoBehaviour {
|
public class BoidController : MonoBehaviour {
|
||||||
@@ -28,17 +29,17 @@ public class BoidController : MonoBehaviour {
|
|||||||
[SerializeField] public bool enableAlignment = true;
|
[SerializeField] public bool enableAlignment = true;
|
||||||
[SerializeField] public bool enableCohesion = true;
|
[SerializeField] public bool enableCohesion = true;
|
||||||
[SerializeField] public bool enableBoundary = true;
|
[SerializeField] public bool enableBoundary = true;
|
||||||
[SerializeField] public bool enableFOVChecks = true;
|
[SerializeField] public bool enableFovChecks = true;
|
||||||
|
|
||||||
[SerializeField] public float boidSeparationRange = 2.3f; // Boid Separation rule's activation distance
|
[SerializeField] public float boidSeparationRange = 2.3f; // Boid Separation rule's activation distance
|
||||||
[SerializeField] public float boundaryForce = 10f; // The force applied when a Boid hits the boundary
|
[SerializeField] public float boundaryForce = 10f; // The force applied when a Boid hits the boundary
|
||||||
[SerializeField] public bool localFlocks = true; // Calculate Local 'Neighborhood' for flocks?
|
[SerializeField] public bool localFlocks = true; // Calculate Local 'Neighborhood' for flocks?
|
||||||
[SerializeField] public bool edgeWrapping = true; // Enforce Edge Wrapping
|
[SerializeField] public bool edgeWrapping = true; // Enforce Edge Wrapping
|
||||||
[SerializeField] public int circleVertexCount = 360; // The number of vertices for circles displayed
|
[SerializeField] public int circleVertexCount = 360; // The number of vertices for circles displayed
|
||||||
[SerializeField] public int arcVertexCount = -1; // The number of vertices for arcs displayed, -1 for auto
|
[SerializeField] public int arcVertexCount = 180; // The number of vertices for arcs displayed, -1 for auto
|
||||||
[SerializeField] public float circleWidth = 0.1f; // Width of circle
|
[SerializeField] public float circleWidth = 0.1f; // Width of circle
|
||||||
[SerializeField] public float maxSteerForce = 10f;
|
[SerializeField] public float maxSteerForce = 10f;
|
||||||
[SerializeField] public float boidFOV = 160;
|
[SerializeField] public float boidFov = 220;
|
||||||
|
|
||||||
|
|
||||||
public Boid focusedBoid; // A focused Boid has special rendering
|
public Boid focusedBoid; // A focused Boid has special rendering
|
||||||
@@ -51,11 +52,6 @@ public class BoidController : MonoBehaviour {
|
|||||||
Gizmos.DrawWireCube(Space.center, Space.size);
|
Gizmos.DrawWireCube(Space.center, Space.size);
|
||||||
Gizmos.DrawWireCube(Boundary.center, Boundary.size);
|
Gizmos.DrawWireCube(Boundary.center, Boundary.size);
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
if (focusedBoid != null)
|
|
||||||
Handles.DrawWireDisc(focusedBoid.transform.position, Vector3.forward, boidGroupRange);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (Cam == null)
|
if (Cam == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -75,6 +71,7 @@ public class BoidController : MonoBehaviour {
|
|||||||
if (focusedBoid != null)
|
if (focusedBoid != null)
|
||||||
focusedBoid.DisableFocusing();
|
focusedBoid.DisableFocusing();
|
||||||
|
|
||||||
|
// Pick a Boid randomly and enable focusing
|
||||||
focusedBoid = boids[Random.Range(0, boids.Count)];
|
focusedBoid = boids[Random.Range(0, boids.Count)];
|
||||||
focusedBoid.EnableFocusing();
|
focusedBoid.EnableFocusing();
|
||||||
}
|
}
|
||||||
@@ -87,25 +84,37 @@ public class BoidController : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Start() {
|
private void Start() {
|
||||||
|
SetupCamera();
|
||||||
|
AddBoids(boidCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Utility function for setting up Camera and Boundary related variables.
|
||||||
|
/// </summary>
|
||||||
|
private void SetupCamera() {
|
||||||
// Setup Camera
|
// Setup Camera
|
||||||
Cam = Camera.main;
|
Cam = Camera.main;
|
||||||
|
|
||||||
|
// Assert that there is an active camera
|
||||||
|
Debug.Assert(Cam != null, nameof(Cam) + " != null");
|
||||||
|
|
||||||
// Size the Rectangle based on the Camera's Orthographic View
|
// Size the Rectangle based on the Camera's Orthographic View
|
||||||
float height = 2f * Cam.orthographicSize;
|
float height = 2f * Cam.orthographicSize;
|
||||||
var size = new Vector2(height * Cam.aspect, height);
|
var size = new Vector2(height * Cam.aspect, height);
|
||||||
Space = new Rect((Vector2) transform.position - size / 2, size);
|
Space = new Rect((Vector2) transform.position - size / 2, size);
|
||||||
Boundary = new Rect(Vector2.zero, Space.size * 0.95f);
|
Boundary = new Rect(Vector2.zero, Space.size * 0.95f);
|
||||||
Boundary.center = Space.center;
|
Boundary.center = Space.center;
|
||||||
|
|
||||||
ShapeDraw.CircleWidth = circleWidth;
|
|
||||||
ShapeDraw.ArcWidth = circleWidth;
|
|
||||||
ShapeDraw.CircleVertexCount = circleVertexCount;
|
|
||||||
// ShapeDraw.ArcVertexCount = arcVertexCount;
|
|
||||||
|
|
||||||
AddBoids(boidCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a number of boids.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
public void AddBoids(int n) {
|
public void AddBoids(int n) {
|
||||||
|
// Skip if negative or zero
|
||||||
|
if (n <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
// Instantiate a Boid prefab within the boundaries randomly
|
// Instantiate a Boid prefab within the boundaries randomly
|
||||||
Vector2 position = RandomPosition() * 0.95f;
|
Vector2 position = RandomPosition() * 0.95f;
|
||||||
@@ -117,7 +126,12 @@ public class BoidController : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a number of boids.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n">Number of Boids to Remove</param>
|
||||||
public void RemoveBoids(int n) {
|
public void RemoveBoids(int n) {
|
||||||
|
// If there are still Boids to remove and the number left to remove is more than 1 (post-decrementing)
|
||||||
while (n-- > 0 && boids.Count >= 1) {
|
while (n-- > 0 && boids.Count >= 1) {
|
||||||
int index = Random.Range(0, boids.Count - 1);
|
int index = Random.Range(0, boids.Count - 1);
|
||||||
|
|
||||||
@@ -132,12 +146,20 @@ public class BoidController : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a Boid at a specific index in the Boids array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index"></param>
|
||||||
private void RemoveBoid(int index) {
|
private void RemoveBoid(int index) {
|
||||||
Boid boid = boids[index];
|
Boid boid = boids[index];
|
||||||
boids.RemoveAt(index);
|
boids.RemoveAt(index);
|
||||||
Destroy(boid.transform.gameObject);
|
Destroy(boid.transform.gameObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a random valid Boid position
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A Vector2 position within the Boid boundary area</returns>
|
||||||
private Vector2 RandomPosition() {
|
private Vector2 RandomPosition() {
|
||||||
return new Vector2(
|
return new Vector2(
|
||||||
Random.Range(-Boundary.size.x, Boundary.size.x) / 2,
|
Random.Range(-Boundary.size.x, Boundary.size.x) / 2,
|
||||||
|
|||||||
@@ -4,11 +4,13 @@
|
|||||||
/// A simple static utility class that assists with drawing shapes using the <c>LineRenderer</c> class.
|
/// A simple static utility class that assists with drawing shapes using the <c>LineRenderer</c> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ShapeDraw {
|
public static class ShapeDraw {
|
||||||
public static float CircleWidth = 1f;
|
// Line width of the Circle and Arc
|
||||||
public static float ArcWidth = 1f;
|
public static float CircleWidth = 0.1f;
|
||||||
public static int CircleVertexCount = 360;
|
public static float ArcWidth = 0.1f;
|
||||||
public static int ArcVertexCount = 77;
|
// Vertex count for Circle and Arc - the precision or detail level the curves have
|
||||||
|
// Low vertex counts are mostly unnoticeable until < 30 vertexes, where eventually squares and triangles appear
|
||||||
|
public static int CircleVertexCount = 180;
|
||||||
|
public static int ArcVertexCount = 90;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draw a Arc aimed straight up with a certain angle width and radius.
|
/// Draw a Arc aimed straight up with a certain angle width and radius.
|
||||||
|
|||||||
Reference in New Issue
Block a user