mirror of
https://github.com/Xevion/Boids.git
synced 2025-12-10 10:06:39 -06:00
Add new Boundary rules
This commit is contained in:
@@ -27,10 +27,10 @@ public class Boid : MonoBehaviour {
|
||||
transform.name = $"Boid {transform.GetSiblingIndex()}"; // Name the Game Object so Boids can be tracked somewhat
|
||||
}
|
||||
|
||||
void OnDrawGizmos() {
|
||||
void OnDrawGizmos() {
|
||||
var transform_ = transform;
|
||||
Handles.Label(transform_.position, $"{transform_.name} {_latestNeighborhoodCount}");
|
||||
}
|
||||
}
|
||||
|
||||
void Update() {
|
||||
// Updates the rotation of the object based on the Velocity
|
||||
@@ -47,11 +47,17 @@ void OnDrawGizmos() {
|
||||
_latestNeighborhoodCount = flock.Count;
|
||||
|
||||
// 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) {
|
||||
Vector2 r1 = Rule1(flock) * _parent.cohesionBias;
|
||||
Vector2 r2 = Rule2(flock) * _parent.separationBias;
|
||||
Vector2 r3 = Rule3(flock) * _parent.alignmentBias;
|
||||
_velocity += r1 + r2 + r3;
|
||||
r1 = Rule1(flock) * _parent.cohesionBias;
|
||||
r2 = Rule2(flock) * _parent.separationBias;
|
||||
r3 = Rule3(flock) * _parent.alignmentBias;
|
||||
_velocity += r1 + r2 + r3 + r4;
|
||||
}
|
||||
else {
|
||||
_velocity += r4;
|
||||
}
|
||||
|
||||
// Limit the Velocity Vector to a certain Magnitude
|
||||
@@ -61,10 +67,11 @@ void OnDrawGizmos() {
|
||||
transform.position = new Vector3(_position.x, _position.y, 0);
|
||||
}
|
||||
|
||||
Wrapping();
|
||||
if (_parent.edgeWrapping)
|
||||
Wrapping();
|
||||
}
|
||||
|
||||
void Wrapping() {
|
||||
private void Wrapping() {
|
||||
if (!_parent.Space.Contains(_position)) {
|
||||
// Activate Wrap, Move
|
||||
Vector2 newPosition = transform.position;
|
||||
@@ -93,20 +100,20 @@ void OnDrawGizmos() {
|
||||
}
|
||||
|
||||
// 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),
|
||||
Vector2.Angle(_position, _parent.Space.center));
|
||||
_centeringVelocity = Util.LimitVelocity(_parent.Space.center - _position, _parent.boidVelocityLimit / 2.0f);
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
return Util.RotateBy(vector, Random.Range(0, 180));
|
||||
}
|
||||
|
||||
// Cohesion: Steer towards center of mass of flock
|
||||
Vector2 Rule1(List<Boid> flock) {
|
||||
private Vector2 Rule1(List<Boid> flock) {
|
||||
Vector2 center = Vector2.zero;
|
||||
foreach (Boid boid in flock)
|
||||
center += boid._position;
|
||||
@@ -115,7 +122,7 @@ void OnDrawGizmos() {
|
||||
}
|
||||
|
||||
// Separation: Steer to avoid other Boids within flock
|
||||
Vector2 Rule2(List<Boid> flock) {
|
||||
private Vector2 Rule2(List<Boid> flock) {
|
||||
Vector2 c = Vector2.zero;
|
||||
foreach (Boid boid in flock) {
|
||||
Vector2 diff = boid._position - this._position;
|
||||
@@ -127,7 +134,7 @@ void OnDrawGizmos() {
|
||||
}
|
||||
|
||||
// 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)
|
||||
return Vector2.zero;
|
||||
|
||||
@@ -138,8 +145,27 @@ void OnDrawGizmos() {
|
||||
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'
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Debug = System.Diagnostics.Debug;
|
||||
using Random = UnityEngine.Random;
|
||||
@@ -7,6 +8,7 @@ using Random = UnityEngine.Random;
|
||||
public class BoidController : MonoBehaviour {
|
||||
// Controller Attributes
|
||||
[NonSerialized] public Rect Space;
|
||||
[NonSerialized] public Rect Boundary;
|
||||
|
||||
// Swarm Attributes
|
||||
public int boidCount = 50;
|
||||
@@ -16,10 +18,13 @@ public class BoidController : MonoBehaviour {
|
||||
public float boidSeparationRange = 2.3f;
|
||||
|
||||
// Bias changes how different rules influence individual Boids more or less
|
||||
public float separationBias = 0.05f;
|
||||
public float alignmentBias = 0.05f;
|
||||
public float cohesionBias = 0.05f;
|
||||
public bool localFlocks = true;
|
||||
[SerializeField] public float separationBias = 0.05f;
|
||||
[SerializeField] public float alignmentBias = 0.05f;
|
||||
[SerializeField] public float cohesionBias = 0.05f;
|
||||
[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 GameObject boidObject; // Boid Object Prefab
|
||||
@@ -29,12 +34,16 @@ public class BoidController : MonoBehaviour {
|
||||
private void OnDrawGizmos() {
|
||||
// Draw a Wire Cube for the Rectangle Area
|
||||
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)
|
||||
return;
|
||||
|
||||
// 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 screenTopRight = Cam.ViewportToWorldPoint(new Vector3(1, 1, position.z));
|
||||
var screenWidth = screenTopRight.x - screenBottomLeft.x;
|
||||
@@ -48,9 +57,11 @@ public class BoidController : MonoBehaviour {
|
||||
|
||||
// Size the Rectangle based on the Camera's Orthographic View
|
||||
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);
|
||||
|
||||
Boundary = new Rect(Vector2.zero, Space.size * 0.95f);
|
||||
Boundary.center = Space.center;
|
||||
|
||||
AddBoids(boidCount);
|
||||
}
|
||||
|
||||
@@ -89,7 +100,7 @@ public class BoidController : MonoBehaviour {
|
||||
|
||||
private Vector2 RandomPosition() {
|
||||
return new Vector2(
|
||||
Random.Range(-Space.size.x, Space.size.x) / 2,
|
||||
Random.Range(-Space.size.y, Space.size.y) / 2);
|
||||
Random.Range(-Boundary.size.x, Boundary.size.x) / 2,
|
||||
Random.Range(-Boundary.size.y, Boundary.size.y) / 2);
|
||||
}
|
||||
}
|
||||
@@ -20,16 +20,19 @@ public class BoidControllerEditor : Editor {
|
||||
}
|
||||
|
||||
// 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.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
|
||||
controller.alignmentBias = EditorGUILayout.Slider("Alignment Bias", controller.alignmentBias, 0.001f, 1.5f);
|
||||
controller.cohesionBias = EditorGUILayout.Slider("Cohesion Bias", controller.cohesionBias, 0.001f, 1.5f);
|
||||
controller.separationBias = EditorGUILayout.Slider("Separation Bias", controller.separationBias, 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, 0.75f);
|
||||
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.edgeWrapping = EditorGUILayout.Toggle("Enforce Wrapping?", controller.edgeWrapping);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class Triangle : MonoBehaviour {
|
||||
public Color fillColor = Color.blue;
|
||||
[NonSerialized] public Color FillColor = Color.red;
|
||||
|
||||
private void Start () {
|
||||
// Create Vector2 vertices
|
||||
@@ -21,7 +22,7 @@ public class Triangle : MonoBehaviour {
|
||||
var indices = triangulator.Triangulate();
|
||||
|
||||
// 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
|
||||
var mesh = new Mesh {
|
||||
|
||||
Reference in New Issue
Block a user