/// <summary> /// Run simulation /// </summary> public IEnumerator CalculateVelocities() { int simulationStep = 0; for (int currentIndex = 0; currentIndex < boids.Count; currentIndex++) { // Optimization trick: in each frame we simulate only small percent of all boids simulationStep++; if (simulationStep > maxSimulationSteps) { simulationStep = 0; yield return(null); } var boid = boids[currentIndex]; // Search for nearest neighbours neighbours.Clear(); for (int i = 0; i < boids.Count; i++) { Boid neighbour = boids[i]; Vector3 toNeighbour = neighbour.position - boid.position; if (toNeighbour.sqrMagnitude < interactionRadius) { neighbours.Add(neighbour); if (neighbours.Count == maxBoids) { break; } } } if (neighbours.Count < 2) { continue; } boid.velocity = Vector3.zero; boid.cohesion = Vector3.zero; boid.separation = Vector3.zero; boid.alignment = Vector3.zero; // Calculate boid parameters int separationCount = 0; for (int i = 0; i < neighbours.Count && i < maxBoids; i++) { Boid neighbour = neighbours[i]; boid.cohesion += neighbour.position; boid.alignment += neighbour.velocity; Vector3 toNeighbour = neighbour.position - boid.position; if (toNeighbour.sqrMagnitude > 0 && toNeighbour.sqrMagnitude < separationDistance * separationDistance) { boid.separation += toNeighbour / toNeighbour.sqrMagnitude; separationCount++; } } // Clamp all parameters to safe values boid.cohesion /= Mathf.Min(neighbours.Count, maxBoids); boid.cohesion = Vector3.ClampMagnitude(boid.cohesion - boid.position, maxSpeed); boid.cohesion *= cohesionCoefficient; if (separationCount > 0) { boid.separation /= separationCount; boid.separation = Vector3.ClampMagnitude(boid.separation, maxSpeed); boid.separation *= separationCoefficient; } boid.alignment /= Mathf.Min(neighbours.Count, maxBoids); boid.alignment = Vector3.ClampMagnitude(boid.alignment, maxSpeed); boid.alignment *= alignmentCoefficient; // Calculate resulting velocity Vector3 velocity = boid.cohesion + boid.separation + boid.alignment; boid.velocity = Vector3.ClampMagnitude(velocity, maxSpeed); if (boid.velocity == Vector3.zero) { // Prevent boids from stopping boid.velocity = Random.onUnitSphere * maxSpeed; } } }