Added new Editor for controlling Boid count, new methods for adding.removing Boids

This commit is contained in:
Xevion
2020-05-18 09:07:06 -05:00
parent 1e3f761b35
commit c2f40ef605
6 changed files with 149 additions and 31 deletions

View File

@@ -15,6 +15,7 @@ public class Boid : MonoBehaviour {
[NonSerialized] private bool _isWrappingY = false; [NonSerialized] private bool _isWrappingY = false;
[NonSerialized] private Renderer[] _renderers; [NonSerialized] private Renderer[] _renderers;
[NonSerialized] private Vector2 _centeringVelocity; [NonSerialized] private Vector2 _centeringVelocity;
[NonSerialized] private int _latestNeighborhoodCount = 0;
private BoidController _parent; private BoidController _parent;
void Start() { void Start() {
@@ -26,14 +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() {
// Handles.color = _isWrappingX || _isWrappingY ? Color.red : Color.white;
// Vector3 viewportPosition = _parent.cam.WorldToViewportPoint(transform.position);
// Handles.Label(transform.position,
// $"{(Vector2) viewportPosition} {(_isWrappingX ? "Y" : "N")} {(_isWrappingY ? "Y" : "N")}");
var transform_ = transform; var transform_ = transform;
Handles.Label(transform_.position, $"{transform_.name}"); 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,6 +44,7 @@ public class Boid : MonoBehaviour {
} }
else { else {
List<Boid> flock = _parent.localFlocks ? GetFlock(_parent.boids, _parent.boidGroupRange) : _parent.boids; List<Boid> flock = _parent.localFlocks ? GetFlock(_parent.boids, _parent.boidGroupRange) : _parent.boids;
_latestNeighborhoodCount = flock.Count;
// Calculate all offsets and multiple by magnitudes given // Calculate all offsets and multiple by magnitudes given
if (flock.Count > 0) { if (flock.Count > 0) {
@@ -70,7 +68,7 @@ public class Boid : MonoBehaviour {
if (!_parent.Space.Contains(_position)) { if (!_parent.Space.Contains(_position)) {
// Activate Wrap, Move // Activate Wrap, Move
Vector2 newPosition = transform.position; Vector2 newPosition = transform.position;
Vector3 viewportPosition = _parent.cam.WorldToViewportPoint(newPosition); Vector3 viewportPosition = _parent.Cam.WorldToViewportPoint(newPosition);
if (!_isWrappingX && (viewportPosition.x > 1 || viewportPosition.x < 0)) { if (!_isWrappingX && (viewportPosition.x > 1 || viewportPosition.x < 0)) {
newPosition.x = -newPosition.x; newPosition.x = -newPosition.x;
@@ -101,6 +99,7 @@ public class Boid : MonoBehaviour {
_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
Vector2 GetRandomVelocity(float magnitude) { 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));

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
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 {
@@ -20,43 +21,43 @@ public class BoidController : MonoBehaviour {
public float cohesionBias = 0.05f; public float cohesionBias = 0.05f;
public bool localFlocks = true; public bool localFlocks = true;
// Boid Object Prefab public Boid focusedBoid; // A focused Boid has special rendering
public GameObject boidObject; public GameObject boidObject; // Boid Object Prefab
[NonSerialized] public List<Boid> boids = new List<Boid>(); // Boid Objects for Updates
// Boid Objects for Updates [NonSerialized] public Camera Cam; // Used for wrapping detection
[NonSerialized] [HideInInspector] public List<Boid> boids = new List<Boid>();
// Used for wrapping
public Camera cam;
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);
if (Cam == null)
return;
// Draw a Wire Cube for the Cam's Viewport Area // Draw a Wire Cube for the Cam's Viewport Area
Vector3 screenBottomLeft = cam.ViewportToWorldPoint(new Vector3(0, 0, transform.position.z)); var position = transform.position;
Vector3 screenTopRight = cam.ViewportToWorldPoint(new Vector3(1, 1, transform.position.z)); 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; var screenWidth = screenTopRight.x - screenBottomLeft.x;
var screenHeight = screenTopRight.y - screenBottomLeft.y; var screenHeight = screenTopRight.y - screenBottomLeft.y;
Gizmos.DrawWireCube(cam.transform.position, new Vector3(screenWidth, screenHeight, 1)); Gizmos.DrawWireCube(Cam.transform.position, new Vector3(screenWidth, screenHeight, 1));
} }
private void Start() { private void Start() {
// Setup Camera // Setup Camera
cam = Camera.main; Cam = Camera.main;
// 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); Vector2 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);
// Add in Boid Objects / Spawn Boid Prefabs AddBoids(boidCount);
for (int i = 0; i < boidCount; i++) { }
// Generate a new position within the Rect boundaries (minus a little)
var position = new Vector2( public void AddBoids(int n) {
Random.Range(-Space.size.x, Space.size.x) / 2 * 0.95f, for (int i = 0; i < n; i++) {
Random.Range(-Space.size.y, Space.size.y) / 2 * 0.95f); // Instantiate a Boid prefab within the boundaries randomly
// Spawn a new Boid prefab Vector2 position = RandomPosition() * 0.95f;
GameObject boid = Instantiate(boidObject, position, Quaternion.identity); GameObject boid = Instantiate(boidObject, position, Quaternion.identity);
// Set parent, add Boid component to Boids list // Set parent, add Boid component to Boids list
@@ -64,4 +65,32 @@ public class BoidController : MonoBehaviour {
boids.Add(boid.GetComponent<Boid>()); boids.Add(boid.GetComponent<Boid>());
} }
} }
public void RemoveBoids(int n) {
print($"Removing {n} boids");
while (n-- > 0 && boids.Count >= 1) {
int index = Random.Range(0, boids.Count - 1);
// Only remove the focused Boid if it is the last one
if (boids[index] == focusedBoid)
if (boids.Count == 1)
RemoveBoid(1);
else
n++;
else
RemoveBoid(index);
}
}
private void RemoveBoid(int index) {
Boid boid = boids[index];
boids.RemoveAt(index);
Destroy(boid.transform.gameObject);
}
private Vector2 RandomPosition() {
return new Vector2(
Random.Range(-Space.size.x, Space.size.x) / 2,
Random.Range(-Space.size.y, Space.size.y) / 2);
}
} }

View File

@@ -0,0 +1,57 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4181400676305357553
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4181400676305357555}
- component: {fileID: 4181400676305357552}
m_Layer: 0
m_Name: BoidController
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4181400676305357555
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4181400676305357553}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &4181400676305357552
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4181400676305357553}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7d72224fef7a4fb4a998b0980fe0eb77, type: 3}
m_Name:
m_EditorClassIdentifier:
boidCount: 1
boidGroupRange: 4.57
boidStartVelocity: 0.05
boidVelocityLimit: 0.5
separationRange: 2.5
separationBias: 0.05
alignmentBias: 0.5
cohesionBias: 0.01
localFlocks: 1
focusedBoid: {fileID: 0}
boidObject: {fileID: 1737515784064720040, guid: 23e1eaaf69d4ef342ac3ef9590f6c642,
type: 3}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 79543cb69dabd5846a1789cccbdeefd8
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
using System;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(BoidController))]
public class BoidControllerEditor : Editor {
public override void OnInspectorGUI() {
BoidController controller = (BoidController) target;
// Boid Count update
EditorGUI.BeginChangeCheck();
controller.boidCount = EditorGUILayout.IntSlider("Boid Count", controller.boidCount, 1, 500);
if (EditorGUI.EndChangeCheck() && Application.isPlaying) {
int diff = controller.boidCount - controller.boids.Count;
Debug.Log($"Difference: {diff}");
if (diff > 1)
controller.AddBoids(diff);
else if (diff < 0)
controller.RemoveBoids(Mathf.Abs(diff));
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6ec8daef16a2459989f9d8b81bb248ea
timeCreated: 1589767516