xxxxxxxxxx
156
let boids = []; // Array to store boid instances
let w = 600, h = 600;
function setup() {
createCanvas(w, h);
background(0);
// Initialize boids with random positions
for (let i = 0; i < 50; i++) {
boids.push(new Boid(random(width), random(height)));
}
}
function draw() {
background(255, 5); // Slight trail effect
boids.forEach(boid => {
boid.flock(boids); // Apply flocking behavior
boid.update(); // Update position and velocity
boid.wrapEdges(); // Wrap around edges of the canvas
boid.show(); // Draw the boid
});
}
// Constants for boid behavior
let M = 2; // Max speed
let F = 0.28; // Max force
let sepDist = 25; // Desired separation distance
let aliDist = 50; // Alignment neighbor distance
let cohDist = 150; // Cohesion neighbor distance
// Class to represent a single boid
class Boid {
constructor(x, y) {
this.position = createVector(x, y);
this.velocity = createVector(random(-1, 1), random(-1, 1));
this.acceleration = createVector(0, 0);
}
// Method to apply flocking behavior
flock(boids) {
let separation = this.separate(boids); // Separation
let alignment = this.align(boids); // Alignment
let cohesion = this.cohesion(boids); // Cohesion
// Adjust weights for the forces
separation.mult(1.5);
alignment.mult(0.99);
cohesion.mult(0.99);
// Apply forces to acceleration
this.acceleration.add(separation);
this.acceleration.add(alignment);
this.acceleration.add(cohesion);
}
// Update position based on velocity and acceleration
update() {
this.velocity.add(this.acceleration);
this.velocity.limit(M); // Limit speed
this.position.add(this.velocity);
this.acceleration.mult(0); // Reset acceleration
}
// Wrap boids around the screen edges
wrapEdges() {
this.position.x = (this.position.x + w) % w;
this.position.y = (this.position.y + h) % h;
}
// Draw boid as a small circle
show() {
fill(255, 0, 0);
ellipse(this.position.x, this.position.y, 10);
}
// Separation behavior: Avoid crowding neighbors
separate(boids) {
let steer = createVector(0, 0);
let count = 0;
boids.forEach(other => {
let distance = p5.Vector.dist(this.position, other.position);
if (distance > 0 && distance < sepDist) {
let diff = p5.Vector.sub(this.position, other.position);
diff.normalize();
diff.div(distance);
steer.add(diff);
count++;
}
});
if (count > 0) steer.div(count);
if (steer.mag() > 0) {
steer.normalize();
steer.mult(M);
steer.sub(this.velocity);
steer.limit(F);
}
return steer;
}
// Alignment behavior: Steer towards the average heading of local flockmates
align(boids) {
let sum = createVector(0, 0);
let count = 0;
boids.forEach(other => {
let distance = p5.Vector.dist(this.position, other.position);
if (distance > 0 && distance < aliDist) {
sum.add(other.velocity);
count++;
}
});
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(M);
let steer = p5.Vector.sub(sum, this.velocity);
steer.limit(F);
return steer;
}
return createVector(0, 0);
}
// Cohesion behavior: Steer towards the average position of local flockmates
cohesion(boids) {
let sum = createVector(0, 0);
let count = 0;
boids.forEach(other => {
let distance = p5.Vector.dist(this.position, other.position);
if (distance > 0 && distance < cohDist) {
sum.add(other.position);
count++;
}
});
if (count > 0) {
sum.div(count);
return this.seek(sum);
}
return createVector(0, 0);
}
// Seek method to steer boid towards a target position
seek(target) {
let desired = p5.Vector.sub(target, this.position);
desired.normalize();
desired.mult(M);
let steer = p5.Vector.sub(desired, this.velocity);
steer.limit(F);
return steer;
}
}
// Function to add a new boid on mouse drag
function mouseDragged() {
boids.push(new Boid(mouseX, mouseY));
}