Beispiel #1
0
        /// <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;
                }
            }
        }