Title: Flocking Birds Simulation in Nature

Project Goal:
This project simulates a flocking system, inspired by bird flocks in nature. The Boid system uses basic flocking rules observed in real-world physics and biology, such as alignment, cohesion, and separation.
The simulation explores how agents (birds) interact with their environment and each other using vectors, randomness, and user controls.

Project Brief:
Create a sketch that would simulate an existing natural system - look at physics, biology, and other natural sciences for good examples. Start with the environment - where is the system situated? What are the forces the environment might exert on the system? Examine the agents in the system, their relationships to each other and the environment they are in. The look at how this system would develop over time. What are the rules that you are going to come up with, what are the parameters you are going to feed into them and what effect will the changes have on the development of the system.
• create classes of entities to represent the components of the system
• use vectors to represent forces existing in the system
• use randomness or noise to generate at least one
• add direct or indirect mouse or keyboard controls
Inspiration:
The flocking behavior of birds is an emergent behavior seen in nature, where individual agents (birds) follow simple rules:
1. Alignment: Align their direction with nearby birds.
2. Cohesion: Move towards the average position of nearby birds.
3. Separation: Maintain a safe distance to avoid collisions.

Forces in the System:
1. The environment is a 2D open space (canvas).
2. Vectors simulate the position, velocity, and acceleration of each bird.
3. Randomness in initial placement and direction mimics the unpredictability of real-world movement.
Entities in the System:
• Boid Class: Represents an individual bird with position, velocity, and acceleration.

• Forces:
• align(): Aligns the boid's direction with its neighbors.
• cohesion(): Moves the boid towards the average position of neighbors.
• separation(): Ensures the boid maintains safe distances.

• Environment: Wrap-around edges ensure birds reappear on the opposite side of the canvas.
P5.JS Code:

// Boid class represents each bird in the flock
class Boid {
  // Constructor to initialize boid's position, velocity, and acceleration
  
  constructor() {
    this.position = createVector(random(width), random(height));
    this.velocity = p5.Vector.random2D();
    this.velocity.setMag(random(2, 4));
    this.acceleration = createVector();
    this.maxForce = 0.2; // Maximum steering force
    this.maxSpeed = 4;   // Maximum speed
  }
// Function for alignment behavior
  align(boids) {
    let perceptionRadius = 50;
    let steering = createVector();
    let total = 0;
    for (let other of boids) {
      let d = dist(this.position.x, this.position.y, other.position.x, other.position.y);
      if (other != this && d < perceptionRadius) {
        steering.add(other.velocity);
        total++;
      }
    }
    if (total > 0) {
      steering.div(total);
      steering.setMag(this.maxSpeed);
      steering.sub(this.velocity);
      steering.limit(this.maxForce);
    }
    return steering;
  }
  // Cohesion behavior
  cohesion(boids) {
    let perceptionRadius = 50;
    let steering = createVector();
    let total = 0;
    for (let other of boids) {
      let d = dist(this.position.x, this.position.y, other.position.x, other.position.y);
      if (other != this && d < perceptionRadius) {
        steering.add(other.position);
        total++;
      }
    }
    if (total > 0) {
      steering.div(total);
      steering.sub(this.position);
      steering.setMag(this.maxSpeed);
      steering.sub(this.velocity);
      steering.limit(this.maxForce);
    }
    return steering;
  }
  // Separation behavior
  separation(boids) {
    let perceptionRadius = 25;
    let steering = createVector();
    let total = 0;
    for (let other of boids) {
      let d = dist(this.position.x, this.position.y, other.position.x, other.position.y);
      if (other != this && d < perceptionRadius) {
        let diff = p5.Vector.sub(this.position, other.position);
        diff.div(d);
        steering.add(diff);
        total++;
      }
    }
    if (total > 0) {
      steering.div(total);
      steering.setMag(this.maxSpeed);
      steering.sub(this.velocity);
      steering.limit(this.maxForce);
    }
    return steering;
  }
  // Apply the forces to the boid
  flock(boids) {
    let alignment = this.align(boids);
    let cohesion = this.cohesion(boids);
    let separation = this.separation(boids);
    // Adjust weights
    alignment.mult(1.0);
    cohesion.mult(1.0);
    separation.mult(1.5);
    this.acceleration.add(alignment);
    this.acceleration.add(cohesion);
    this.acceleration.add(separation);
  }
  // Update the boid's position
  update() {
    this.position.add(this.velocity);
    this.velocity.add(this.acceleration);
    this.velocity.limit(this.maxSpeed);
    this.acceleration.mult(0);
  }
  // Draw the boid on the canvas
  show() {
    strokeWeight(8);
    stroke(0, 0.8, 0.9);
    point(this.position.x, this.position.y);
  }
  // Wrap around the edges of the canvas
  edges() {
    if (this.position.x > width) this.position.x = 0;
    if (this.position.x < 0) this.position.x = width;
    if (this.position.y > height) this.position.y = 0;
    if (this.position.y < 0) this.position.y = height;
  }
}

You may also like

Back to Top