/// <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(); } }