Add new Boundary rules

This commit is contained in:
Xevion
2020-05-18 12:48:41 -05:00
parent ceebb7c974
commit 87da645dcd
4 changed files with 73 additions and 32 deletions

View File

@@ -27,10 +27,10 @@ public class Boid : MonoBehaviour {
transform.name = $"Boid {transform.GetSiblingIndex()}"; // Name the Game Object so Boids can be tracked somewhat transform.name = $"Boid {transform.GetSiblingIndex()}"; // Name the Game Object so Boids can be tracked somewhat
} }
void OnDrawGizmos() { void OnDrawGizmos() {
var transform_ = transform; var transform_ = transform;
Handles.Label(transform_.position, $"{transform_.name} {_latestNeighborhoodCount}"); Handles.Label(transform_.position, $"{transform_.name} {_latestNeighborhoodCount}");
} }
void Update() { void Update() {
// Updates the rotation of the object based on the Velocity // Updates the rotation of the object based on the Velocity
@@ -47,11 +47,17 @@ void OnDrawGizmos() {
_latestNeighborhoodCount = flock.Count; _latestNeighborhoodCount = flock.Count;
// Calculate all offsets and multiple by magnitudes given // Calculate all offsets and multiple by magnitudes given
Vector2 r1, r2, r3, r4;
r4 = _parent.Boundary.Contains(_position) ? Vector2.zero : RuleBound() * _parent.boundaryBias;
if (flock.Count > 0) { if (flock.Count > 0) {
Vector2 r1 = Rule1(flock) * _parent.cohesionBias; r1 = Rule1(flock) * _parent.cohesionBias;
Vector2 r2 = Rule2(flock) * _parent.separationBias; r2 = Rule2(flock) * _parent.separationBias;
Vector2 r3 = Rule3(flock) * _parent.alignmentBias; r3 = Rule3(flock) * _parent.alignmentBias;
_velocity += r1 + r2 + r3; _velocity += r1 + r2 + r3 + r4;
}
else {
_velocity += r4;
} }
// Limit the Velocity Vector to a certain Magnitude // Limit the Velocity Vector to a certain Magnitude
@@ -61,10 +67,11 @@ void OnDrawGizmos() {
transform.position = new Vector3(_position.x, _position.y, 0); transform.position = new Vector3(_position.x, _position.y, 0);
} }
if (_parent.edgeWrapping)
Wrapping(); Wrapping();
} }
void Wrapping() { private void Wrapping() {
if (!_parent.Space.Contains(_position)) { if (!_parent.Space.Contains(_position)) {
// Activate Wrap, Move // Activate Wrap, Move
Vector2 newPosition = transform.position; Vector2 newPosition = transform.position;
@@ -93,20 +100,20 @@ void OnDrawGizmos() {
} }
// When Wrapping, this Velocity directs the Boid to the center of the Rectangle // When Wrapping, this Velocity directs the Boid to the center of the Rectangle
void UpdateCenteringVelocity() { private void UpdateCenteringVelocity() {
_centeringVelocity = Util.RotateBy(new Vector2(_parent.boidVelocityLimit, _parent.boidVelocityLimit), _centeringVelocity = Util.RotateBy(new Vector2(_parent.boidVelocityLimit, _parent.boidVelocityLimit),
Vector2.Angle(_position, _parent.Space.center)); Vector2.Angle(_position, _parent.Space.center));
_centeringVelocity = Util.LimitVelocity(_parent.Space.center - _position, _parent.boidVelocityLimit / 2.0f); _centeringVelocity = Util.LimitVelocity(_parent.Space.center - _position, _parent.boidVelocityLimit / 2.0f);
} }
// Returns a velocity (Vector2) at a random angle with a specific overall magnitude // Returns a velocity (Vector2) at a random angle with a specific overall magnitude
Vector2 GetRandomVelocity(float magnitude) { private Vector2 GetRandomVelocity(float magnitude) {
Vector2 vector = new Vector2(magnitude, magnitude); Vector2 vector = new Vector2(magnitude, magnitude);
return Util.RotateBy(vector, Random.Range(0, 180)); return Util.RotateBy(vector, Random.Range(0, 180));
} }
// Cohesion: Steer towards center of mass of flock // Cohesion: Steer towards center of mass of flock
Vector2 Rule1(List<Boid> flock) { private Vector2 Rule1(List<Boid> flock) {
Vector2 center = Vector2.zero; Vector2 center = Vector2.zero;
foreach (Boid boid in flock) foreach (Boid boid in flock)
center += boid._position; center += boid._position;
@@ -115,7 +122,7 @@ void OnDrawGizmos() {
} }
// Separation: Steer to avoid other Boids within flock // Separation: Steer to avoid other Boids within flock
Vector2 Rule2(List<Boid> flock) { private Vector2 Rule2(List<Boid> flock) {
Vector2 c = Vector2.zero; Vector2 c = Vector2.zero;
foreach (Boid boid in flock) { foreach (Boid boid in flock) {
Vector2 diff = boid._position - this._position; Vector2 diff = boid._position - this._position;
@@ -127,7 +134,7 @@ void OnDrawGizmos() {
} }
// Alignment: Steer to align with the average heading of the flock // Alignment: Steer to align with the average heading of the flock
Vector3 Rule3(List<Boid> flock) { public Vector2 Rule3(List<Boid> flock) {
if (flock.Count == 0) if (flock.Count == 0)
return Vector2.zero; return Vector2.zero;
@@ -138,8 +145,27 @@ void OnDrawGizmos() {
return (perceived - _velocity) / 8.0f; return (perceived - _velocity) / 8.0f;
} }
// Asks Boids to stay within the Boundaries set
private Vector2 RuleBound() {
Vector2 vector = Vector2.zero;
// Boundary X Force
if (_position.x < _parent.Boundary.xMin)
vector.x = _parent.boundaryForce;
else if (_position.x > _parent.Boundary.xMax)
vector.x = -_parent.boundaryForce;
// Boundary Y Force
if (_position.y < _parent.Boundary.yMin)
vector.y = _parent.boundaryForce;
else if (_position.y > _parent.Boundary.yMax)
vector.y = -_parent.boundaryForce;
return vector;
}
// Returns a list of boids within a certain radius of the Boid, representing it's local 'flock' // Returns a list of boids within a certain radius of the Boid, representing it's local 'flock'
List<Boid> GetFlock(List<Boid> boids, float radius) { private List<Boid> GetFlock(List<Boid> boids, float radius) {
return boids.Where(boid => boid != this && Vector2.Distance(this._position, boid._position) <= radius).ToList(); return boids.Where(boid => boid != this && Vector2.Distance(this._position, boid._position) <= radius).ToList();
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEditor;
using UnityEngine; using UnityEngine;
using Debug = System.Diagnostics.Debug; using Debug = System.Diagnostics.Debug;
using Random = UnityEngine.Random; using Random = UnityEngine.Random;
@@ -7,6 +8,7 @@ using Random = UnityEngine.Random;
public class BoidController : MonoBehaviour { public class BoidController : MonoBehaviour {
// Controller Attributes // Controller Attributes
[NonSerialized] public Rect Space; [NonSerialized] public Rect Space;
[NonSerialized] public Rect Boundary;
// Swarm Attributes // Swarm Attributes
public int boidCount = 50; public int boidCount = 50;
@@ -16,10 +18,13 @@ public class BoidController : MonoBehaviour {
public float boidSeparationRange = 2.3f; public float boidSeparationRange = 2.3f;
// Bias changes how different rules influence individual Boids more or less // Bias changes how different rules influence individual Boids more or less
public float separationBias = 0.05f; [SerializeField] public float separationBias = 0.05f;
public float alignmentBias = 0.05f; [SerializeField] public float alignmentBias = 0.05f;
public float cohesionBias = 0.05f; [SerializeField] public float cohesionBias = 0.05f;
public bool localFlocks = true; [SerializeField] public float boundaryBias = 1f;
[SerializeField] public float boundaryForce = 10f;
[SerializeField] public bool localFlocks = true;
[SerializeField] public bool edgeWrapping = true;
public Boid focusedBoid; // A focused Boid has special rendering public Boid focusedBoid; // A focused Boid has special rendering
public GameObject boidObject; // Boid Object Prefab public GameObject boidObject; // Boid Object Prefab
@@ -29,12 +34,16 @@ public class BoidController : MonoBehaviour {
private void OnDrawGizmos() { private void OnDrawGizmos() {
// Draw a Wire Cube for the Rectangle Area // Draw a Wire Cube for the Rectangle Area
Gizmos.DrawWireCube(Space.center, Space.size); Gizmos.DrawWireCube(Space.center, Space.size);
Gizmos.DrawWireCube(Boundary.center, Boundary.size);
if (focusedBoid != null)
Handles.DrawWireDisc(focusedBoid.transform.position, Vector3.forward, boidGroupRange);
if (Cam == null) if (Cam == null)
return; return;
// Draw a Wire Cube for the Cam's Viewport Area // Draw a Wire Cube for the Cam's Viewport Area
var position = transform.position; Vector3 position = transform.position;
Vector3 screenBottomLeft = Cam.ViewportToWorldPoint(new Vector3(0, 0, position.z)); Vector3 screenBottomLeft = Cam.ViewportToWorldPoint(new Vector3(0, 0, position.z));
Vector3 screenTopRight = Cam.ViewportToWorldPoint(new Vector3(1, 1, position.z)); Vector3 screenTopRight = Cam.ViewportToWorldPoint(new Vector3(1, 1, position.z));
var screenWidth = screenTopRight.x - screenBottomLeft.x; var screenWidth = screenTopRight.x - screenBottomLeft.x;
@@ -48,8 +57,10 @@ public class BoidController : MonoBehaviour {
// 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;
Vector2 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.center = Space.center;
AddBoids(boidCount); AddBoids(boidCount);
} }
@@ -89,7 +100,7 @@ public class BoidController : MonoBehaviour {
private Vector2 RandomPosition() { private Vector2 RandomPosition() {
return new Vector2( return new Vector2(
Random.Range(-Space.size.x, Space.size.x) / 2, Random.Range(-Boundary.size.x, Boundary.size.x) / 2,
Random.Range(-Space.size.y, Space.size.y) / 2); Random.Range(-Boundary.size.y, Boundary.size.y) / 2);
} }
} }

View File

@@ -20,16 +20,19 @@ public class BoidControllerEditor : Editor {
} }
// Basic Boid Controller Attributes // Basic Boid Controller Attributes
controller.boidGroupRange = EditorGUILayout.Slider("Group Range", controller.boidGroupRange, 0.01f, 25.0f); controller.boidGroupRange = EditorGUILayout.Slider("Group Range", controller.boidGroupRange, 0.01f, 10.0f);
controller.boidStartVelocity = EditorGUILayout.Slider("Start Velocity", controller.boidStartVelocity, 0.01f, 5.0f); controller.boidStartVelocity = EditorGUILayout.Slider("Start Velocity", controller.boidStartVelocity, 0.01f, 5.0f);
controller.boidVelocityLimit = EditorGUILayout.Slider("Max Velocity", controller.boidVelocityLimit, 0.01f, 7.5f); controller.boidVelocityLimit = EditorGUILayout.Slider("Max Velocity", controller.boidVelocityLimit, 0.01f, 7.5f);
controller.boidSeparationRange = EditorGUILayout.Slider("Separation Range", controller.boidSeparationRange, 0.01f, 25.0f); controller.boidSeparationRange = EditorGUILayout.Slider("Separation Range", controller.boidSeparationRange, 0.01f, 5.0f);
controller.boundaryForce = EditorGUILayout.Slider("Boundary Force", controller.boundaryForce, 0.5f, 5.0f);
// Boid Bias Attributes // Boid Bias Attributes
controller.alignmentBias = EditorGUILayout.Slider("Alignment Bias", controller.alignmentBias, 0.001f, 1.5f); controller.alignmentBias = EditorGUILayout.Slider("Alignment Bias", controller.alignmentBias, 0.001f, 0.75f);
controller.cohesionBias = EditorGUILayout.Slider("Cohesion Bias", controller.cohesionBias, 0.001f, 1.5f); controller.cohesionBias = EditorGUILayout.Slider("Cohesion Bias", controller.cohesionBias, 0.001f, 0.75f);
controller.separationBias = EditorGUILayout.Slider("Separation Bias", controller.separationBias, 0.001f, 1.5f); controller.separationBias = EditorGUILayout.Slider("Separation Bias", controller.separationBias, 0.001f, 0.75f);
controller.boundaryBias = EditorGUILayout.Slider("Boundary Bias", controller.boundaryBias, 0.01f, 1.5f);
controller.localFlocks = EditorGUILayout.Toggle("Use Groups?", controller.localFlocks); controller.localFlocks = EditorGUILayout.Toggle("Use Groups?", controller.localFlocks);
controller.edgeWrapping = EditorGUILayout.Toggle("Enforce Wrapping?", controller.edgeWrapping);
} }
} }

View File

@@ -1,10 +1,11 @@
using System.Collections; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
public class Triangle : MonoBehaviour { public class Triangle : MonoBehaviour {
public Color fillColor = Color.blue; [NonSerialized] public Color FillColor = Color.red;
private void Start () { private void Start () {
// Create Vector2 vertices // Create Vector2 vertices
@@ -21,7 +22,7 @@ public class Triangle : MonoBehaviour {
var indices = triangulator.Triangulate(); var indices = triangulator.Triangulate();
// Generate a color for each vertex // Generate a color for each vertex
var colors = Enumerable.Repeat(fillColor, vertices3D.Length).ToArray(); var colors = Enumerable.Repeat(FillColor, vertices3D.Length).ToArray();
// Create the mesh // Create the mesh
var mesh = new Mesh { var mesh = new Mesh {