xxxxxxxxxx
217
class Boid {
constructor(x, y, colorIndex) {
this.acceleration = createVector(0, 0);
this.velocity = createVector(random(-1, 1), random(-1, 1));
this.position = createVector(x, y);
this.maxSpeed = 3;
this.maxForce = 0.05;
this.color = colorIndex % 250; // Assigns a color based on an index
}
// Main method that updates and renders the boid
run(boids, obstacles) {
this.flock(boids, obstacles);
this.update();
this.wrapAround();
this.display();
}
// Applies a force to the boid
applyForce(force) {
this.acceleration.add(force);
}
flock(boids, obstacles) {
let sep = this.separate(boids);
let ali = this.align(boids);
let coh = this.cohesion(boids);
let avoid = this.avoidObstacles(obstacles);
sep.mult(1.5);
ali.mult(0.75);
coh.mult(1.0);
avoid.mult(2); // Adjust weight for avoidance as needed
this.applyForce(sep);
this.applyForce(ali);
this.applyForce(coh);
this.applyForce(avoid);
}
// Updates position and velocity
update() {
this.velocity.add(this.acceleration);
this.velocity.limit(this.maxSpeed);
this.position.add(this.velocity);
this.acceleration.mult(0);
}
// Renders the boid with dynamic size based on its speed
display() {
// Calculate the size based on velocity
let speed = this.velocity.mag();
let size = map(speed, 0, this.maxSpeed, 2, 10); // Map speed to a reasonable size range
// Calculate hue for color (keep the same color logic as before)
let time = millis() / 1000;
let timeFactor = (sin(time + this.color) + 1) / 2;
let velFactor = speed / this.maxSpeed;
let hue = (this.color + 360 * timeFactor + 180 * velFactor) % 360;
// Set color and size
colorMode(HSB, 360, 100, 100);
stroke(hue, 80, 90);
strokeWeight(size);
// Draw the boid
push();
translate(this.position.x, this.position.y);
point(0, 0);
pop();
// Reset color mode if needed
colorMode(RGB, 255);
}
// Wrap around the screen edges
wrapAround() {
let r = 4;
if (this.position.x < -r) this.position.x = width + r;
if (this.position.y < -r) this.position.y = height + r;
if (this.position.x > width + r) this.position.x = -r;
if (this.position.y > height + r) this.position.y = -r;
}
// Separation behavior
separate(boids) {
let desiredSeparation = 25;
let steer = createVector(0, 0);
let count = 0;
for (let other of boids) {
let d = p5.Vector.dist(this.position, other.position);
if (d > 0 && d < desiredSeparation) {
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 behavior
align(boids) {
let neighborDistance = 40;
let sum = createVector(0, 0);
let count = 0;
for (let other of boids) {
let d = p5.Vector.dist(this.position, other.position);
if (d > 0 && d < neighborDistance) {
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 behavior
cohesion(boids) {
let neighborDistance = 50;
let sum = createVector(0, 0);
let count = 0;
for (let other of boids) {
let d = p5.Vector.dist(this.position, other.position);
if (d > 0 && d < neighborDistance) {
sum.add(other.position);
count++;
}
}
if (count > 0) {
sum.div(count);
return this.seek(sum);
} else {
return createVector(0, 0);
}
}
// Method to avoid obstacles
// In the Boid class
// Method to avoid line obstacles
avoidObstacles(obstacles) {
let steer = createVector(0, 0);
let count = 0;
let safeDistance = 30; // Increase safe distance for early avoidance
obstacles.forEach(obstacle => {
let closestPoint = this.closestPointOnLine(this.position, obstacle.start, obstacle.end);
let d = p5.Vector.dist(this.position, closestPoint);
if (d < safeDistance) {
let diff = p5.Vector.sub(this.position, closestPoint);
diff.normalize();
diff.div(d); // Stronger weighting by distance
steer.add(diff);
count++;
}
});
if (count > 0) {
steer.div(count);
steer.setMag(this.maxSpeed * 1.5); // Increase the magnitude of the steering force
steer.sub(this.velocity);
steer.limit(this.maxForce * 1.5); // Increase the maximum force limit
}
return steer;
}
// Helper method to find the closest point on a line segment to a given point
closestPointOnLine(point, lineStart, lineEnd) {
let lineVector = p5.Vector.sub(lineEnd, lineStart);
let pointVector = p5.Vector.sub(point, lineStart);
let lineLengthSquared = lineVector.magSq();
let dotProduct = pointVector.dot(lineVector);
let t = constrain(dotProduct / lineLengthSquared, 0, 1);
return p5.Vector.add(lineStart, lineVector.mult(t));
}
// Method to move towards a target
seek(target, multiplier = 1) {
let desired = p5.Vector.sub(target, this.position);
desired.normalize();
desired.mult(this.maxSpeed * multiplier);
let steer = p5.Vector.sub(desired, this.velocity);
steer.limit(this.maxForce * multiplier);
return steer;
}
}