Created
November 4, 2024 01:35
-
-
Save mminer/227ce5f4eaaf70d382e6823118ae031f to your computer and use it in GitHub Desktop.
2D flocking implementation for Unity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public partial class Flock : MonoBehaviour | |
{ | |
[SerializeField, Min(0)] float spawnRadius = 5f; | |
[SerializeField, Min(1)] int unitCount = 50; | |
[SerializeField] Transform unitPrefab; | |
[Header("Unit")] | |
[SerializeField, Range(0, 360)] float fieldOfView = 270f; | |
[SerializeField, Min(0)] float separationRadius = 1f; | |
[SerializeField, Min(0)] float sightRadius = 3f; | |
[SerializeField, Min(0)] float speed = 1f; | |
[SerializeField, Min(0)] float steeringForce = 1f; | |
Transform[] units; | |
void Start() | |
{ | |
InstantiateUnits(); | |
} | |
void Update() | |
{ | |
foreach (var unit in units) | |
{ | |
UpdateUnit(unit); | |
} | |
} | |
void InstantiateUnits() | |
{ | |
units = new Transform[unitCount]; | |
for (var i = 0; i < unitCount; i++) | |
{ | |
var position = Random.insideUnitCircle * spawnRadius; | |
var rotation = Quaternion.Euler(0, 0, Random.Range(0, 360)); | |
units[i] = Instantiate(unitPrefab, position, rotation, transform); | |
} | |
} | |
void UpdateUnit(Transform unit) | |
{ | |
var unitPosition = (Vector2)unit.position; | |
var unitDirection = (Vector2)unit.up; | |
var neighborCount = 0; | |
var averageNeighborPosition = Vector2.zero; | |
var averageNeighborDirection = Vector2.zero; | |
var separation = Vector2.zero; | |
foreach (var otherUnit in units) | |
{ | |
if (otherUnit == unit) | |
{ | |
continue; | |
} | |
var otherUnitPosition = (Vector2)otherUnit.position; | |
var otherUnitDirection = (Vector2)otherUnit.up; | |
var directionToOther = otherUnitPosition - unitPosition; | |
var sqrDistanceToOther = directionToOther.sqrMagnitude; | |
var isWithinSightRadius = sqrDistanceToOther <= sightRadius * sightRadius; | |
if (!isWithinSightRadius) | |
{ | |
continue; | |
} | |
var angleToOther = Vector2.Angle(unitDirection, directionToOther); | |
var isWithinFieldOfView = angleToOther <= fieldOfView / 2; | |
if (!isWithinFieldOfView) | |
{ | |
continue; | |
} | |
neighborCount++; | |
averageNeighborPosition += otherUnitPosition; | |
averageNeighborDirection += otherUnitDirection; | |
var isWithinSeparationRadius = sqrDistanceToOther <= separationRadius * separationRadius; | |
if (isWithinSeparationRadius) | |
{ | |
separation -= directionToOther * separationRadius / sqrDistanceToOther; | |
} | |
Debug.DrawLine(unitPosition, otherUnitPosition, Color.green); | |
} | |
if (neighborCount > 0) | |
{ | |
averageNeighborPosition /= neighborCount; | |
averageNeighborDirection /= neighborCount; | |
var cohesion = (averageNeighborPosition - unitPosition).normalized; | |
var alignment = averageNeighborDirection.normalized; | |
unit.up = Vector3.Lerp(unit.up, cohesion + alignment + separation, steeringForce * Time.deltaTime); | |
} | |
unit.position += unit.up * (speed * Time.deltaTime); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if UNITY_EDITOR | |
using UnityEngine; | |
using UnityEditor; | |
public partial class Flock | |
{ | |
void OnDrawGizmos() | |
{ | |
if (units == null) | |
{ | |
return; | |
} | |
Handles.color = Color.red; | |
foreach (var unit in units) | |
{ | |
Handles.DrawLine(unit.position, unit.position + (unit.up * sightRadius)); | |
var arcStartDirection = Quaternion.Euler(0, 0, -fieldOfView / 2) * unit.up; | |
var arcEndDirection = Quaternion.Euler(0, 0, fieldOfView / 2) * unit.up; | |
Handles.DrawWireArc(unit.position, Vector3.forward, arcStartDirection, fieldOfView, separationRadius); | |
Handles.DrawWireArc(unit.position, Vector3.forward, arcStartDirection, fieldOfView, sightRadius); | |
var arcStartPosition = unit.position + (arcStartDirection * sightRadius); | |
var arcEndPosition = unit.position + (arcEndDirection * sightRadius); | |
Handles.DrawLine(unit.position, arcStartPosition); | |
Handles.DrawLine(unit.position, arcEndPosition); | |
} | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment