예제 #1
0
    /// <summary>
    /// Update boid using the 3 rules:
    /// - Separation
    /// - Alignment
    /// - Cohesion
    /// </summary>
    /// <param name="boids"> List of all boids in the scene.</param>
    /// <param name="T"> Threshold determining neighborhood distance. </param>
    public void UpdateBoid(Boid boid, List <Boid> boids, float T)
    {
        // =====================
        // Check bounds
        // =====================
        boid.CheckBounds(worldExtents);

        // =====================
        // Check sickness
        // =====================
        bool justSick = boid.justGotSick;

        if (justSick)
        {
            boid.ResetSicknesProbability();
        }

        // =====================
        // Get neighboors
        // =====================
        foreach (Boid b in boids)
        {
            float dist = Vector3.Magnitude(b.transform.position - boid.transform.position);
            if (dist < T && dist > Mathf.Epsilon)
            {
                neighbors.Add(b);
            }

            if (justSick)
            {
                b.ResetSicknesProbability();
            }
        }

        // ==============
        // Obstacles
        // ==============
        Vector3 alignment  = Vector3.zero;
        Vector3 separation = Vector3.zero;
        Vector3 cohesion   = Vector3.zero;

        // Vector3 avoidObstaclesVel = boid.AvoidObstaclesDir(rayCastLength);
        Vector3 avoidObstaclesVel = Vector3.zero;

        if (this.HealingCircle.gameObject.activeSelf)
        {
            avoidObstaclesVel = boid.AvoidObstaclesDir(this.HealingCircle.transform.position);
            avoidObstaclesVel = boid.Steer(avoidObstaclesVel.normalized * maxSpeed, maxForce);
        }

        if (neighbors.Count == 0)
        {
            // boid.ApplyAcceleration(alignment, wAlignment, separation, wSeparation, cohesion, wCohesion, avoidObstaclesVel, wAvoidObst, maxSpeed);
            // Clean up neighbors
            this.neighbors.Clear();
            return;
        }

        // ============================
        // 3 RULES
        // ============================
        // =====================
        // Alignment - direction
        // =====================
        foreach (Boid b in neighbors)
        {
            Vector3 rb_vel = b.velocity;
            alignment += rb_vel;
        }
        alignment /= boids.Count;
        alignment  = boid.Steer(alignment.normalized * maxSpeed, maxForce);

        // =====================
        // Separation
        // =====================
        float half = T * this.separatorNeighborsPercent;

        foreach (Boid b in neighbors)
        {
            Vector3 dir  = boid.transform.position - b.transform.position;
            float   dist = Vector3.Magnitude(dir);
            if (dist < half)
            {
                separation += dir.normalized / dist;

                // Push sickness prob if Im sick
                if (justSick)
                {
                    b.PushSicknessProbability(T * 2 - dist);
                }
            }
        }
        separation = boid.Steer(separation.normalized * maxSpeed, maxForce);

        // =====================
        // Cohesion
        // =====================
        Vector3 centroid     = Vector3.zero;
        float   halfCohesion = T * (0.5f);
        int     count        = 0;

        foreach (Boid b in neighbors)
        {
            Vector3 dir  = boid.transform.position - b.transform.position;
            float   dist = Vector3.Magnitude(dir);
            if (dist < halfCohesion)
            {
                centroid += b.transform.position;
                count++;
            }
        }
        if (count == 0)
        {
            cohesion = Vector3.zero;
        }
        else
        {
            centroid /= count;//neighbors.Count;
            cohesion  = boid.Steer((centroid - boid.transform.position).normalized * maxSpeed, maxForce);
        }

        // =====================
        // Apply
        // =====================
        boid.ApplyAcceleration(alignment, wAlignment, separation, currentSeparationWeight, cohesion, wCohesion, avoidObstaclesVel, wAvoidObst, maxSpeed);
        // boid.ApplyAcceleration(alignment, wAlignment, separation, wSeparation, cohesion, wCohesion, Vector3.zero, wAvoidObst, maxSpeed);
        // Clean up neighbors
        this.neighbors.Clear();

        // ==================
        // Pay if using separation
        // ==================
        if (separateMode)
        {
            GameManager.Instance.UseSeparator();
        }
    }