xxxxxxxxxx
202
class Boid {
constructor(x, y, color) {
this.acceleration = createVector(0, 0);
this.velocity = createVector(random(-1, 1), random(-1, 1));
this.position = createVector(x, y);
this.r = 3.0;
this.maxSpeed = 3; // Maximum speed
this.maxForce = 0.05; // Maximum steering force
this.color = color;
}
run(boids) {
this.flock(boids);
this.update();
this.borders();
this.show();
}
applyForce(force) {
// We could add mass here if we want A = F / M
this.acceleration.add(force);
}
// Flocking behavior methods now account for color grouping
flock(boids) {
let sep = this.separate(boids);
let ali = this.align(boids);
let coh = this.cohere(boids);
let attraction = this.seek(createVector(mouseX, mouseY)); // Attraction towards mouse
// Behavior Probability
sep.mult(1.5);
ali.mult(1.0);
coh.mult(1.0);
attraction.mult(0.3);
// Apply All Forces to Boid
this.applyForce(sep);
this.applyForce(ali);
this.applyForce(coh);
this.applyForce(attraction);
}
// Method to update location
update() {
// Update velocity
this.velocity.add(this.acceleration);
// Limit speed
this.velocity.limit(this.maxSpeed);
this.position.add(this.velocity);
// Reset accelertion to 0 each cycle
this.acceleration.mult(0);
}
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
seek(target) {
let desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target
// Normalize desired and scale to maximum speed
desired.normalize();
desired.mult(this.maxSpeed);
// Steering = Desired minus Velocity
let steer = p5.Vector.sub(desired, this.velocity);
steer.limit(this.maxForce); // Limit to maximum steering force
return steer;
}
//Draw Squares with certain color
show() {
let angle = this.velocity.heading();
let emoji = this.color === "#C96868" ? "" : "";
stroke(0);
push();
translate(this.position.x, this.position.y);
rotate(angle);
beginShape();
textSize(this.r * 3); // Adjust size if needed
textAlign(CENTER, CENTER);
text(emoji, this.position.x, this.position.y);
endShape(CLOSE);
pop();
}
// Edge Checking
borders() {
// Check left and right edges
if (this.position.x <= this.r || this.position.x >= width - this.r) {
this.velocity.x *= -1; // Reverse x velocity
}
// Check top and bottom edges
if (this.position.y <= this.r || this.position.y >= height - this.r) {
this.velocity.y *= -1; // Reverse y velocity
}
}
// Separation
// Method checks for nearby boids
// Separates away if its a different color
separate(boids) {
let desiredSeparation = 25;
let steer = createVector(0, 0);
let count = 0;
for (let i = 0; i < boids.length; i++) {
let other = boids[i];
let d = p5.Vector.dist(this.position, other.position);
if (d > 0 && d < desiredSeparation && other.color === this.color) {
// Only same color
let diff = p5.Vector.sub(this.position, other.position);
diff.normalize();
diff.div(d);
steer.add(diff);
count++;
}
}
if (count > 0) {
steer.div(count);
}
if (steer.mag() > 0) {
steer.normalize();
steer.mult(this.maxSpeed);
steer.sub(this.velocity);
steer.limit(this.maxForce);
}
return steer;
}
// Alignment
// For every nearby boid in the system, calculate the average velocity
align(boids) {
let neighborDistance = 50;
let sum = createVector(0, 0);
let count = 0;
for (let i = 0; i < boids.length; i++) {
let other = boids[i];
let d = p5.Vector.dist(this.position, other.position);
if (d > 0 && d < neighborDistance && other.color === this.color) {
// Only same color
sum.add(other.velocity);
count++;
}
}
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(this.maxSpeed);
let steer = p5.Vector.sub(sum, this.velocity);
steer.limit(this.maxForce);
return steer;
} else {
return createVector(0, 0);
}
}
// Cohesion
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
cohere(boids) {
let neighborDistance = 50;
let sum = createVector(0, 0);
let count = 0;
for (let i = 0; i < boids.length; i++) {
let other = boids[i];
let d = p5.Vector.dist(this.position, other.position);
if (d > 0 && d < neighborDistance && other.color === this.color) {
// Only same color
sum.add(other.position);
count++;
}
}
if (count > 0) {
sum.div(count);
return this.seek(sum);
} else {
return createVector(0, 0);
}
}
//Connect
//Function to connect a string between each boids
connect(boids) {
for (let other of boids) {
let d = p5.Vector.dist(this.position, other.position);
let maxDistance = 100; // Maximum distance for drawing a line
// Only draw line if within maxDistance and the other boid is not itself
if (d > 0 && d < maxDistance) {
stroke(200, 50);
strokeWeight(0.5);
line(
this.position.x,
this.position.y,
other.position.x,
other.position.y
);
}
}
}
}