xxxxxxxxxx
163
class Boid {
constructor(x, y) {
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 = 10; // Maximum speed
this.maxforce = 0.05; // Maximum steering force
this.behaviorIntensity();
}
behaviorIntensity() {
if (maxBoids === 200) { // Low intensity
this.maxspeed = 13;
this.maxforce = 0.04;
this.perceptionRadius = 15;
} else if (maxBoids === 400) { // Medium intensity
this.maxspeed = 25;
this.maxforce = 0.08;
this.perceptionRadius = 25;
} else if (maxBoids === 800) { // High intensity
this.maxspeed = 40;
this.maxforce = 0.15;
this.perceptionRadius = 40;
}
}
run(boid,col) {
this.flock(boid);
this.update();
this.borders();
this.show(col);
}
applyForce(force) {
this.acceleration.add(force);
}
// We accumulate a new acceleration each time based on three rules
flock(boids) {
let sep = this.separate(boids); // Separation
// let ali = this.align(boids); // Alignment
let coh = this.cohere(boids); // Cohesion
// Arbitrarily weight these forces
sep.mult(2.5);
// ali.mult (1.5);
coh.mult(1.0);
// Add the force vectors to acceleration
this.applyForce(sep);
// this.applyForce(ali);
this.applyForce(coh);
}
// 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;
}
show(col) {
let angle = this.velocity.heading();
fill(col);
stroke(0);
push();
translate(this.position.x, this.position.y);
rotate(angle);
beginShape();
vertex(this.r * 2, 0);
vertex(-this.r * 2, -this.r);
vertex(-this.r * 2, this.r);
endShape(CLOSE);
pop();
}
// Wraparound
borders() {
if (this.position.x < -this.r) this.position.x = width + this.r;
if (this.position.y < -this.r) this.position.y = height + this.r;
if (this.position.x > width + this.r) this.position.x = -this.r;
if (this.position.y > height + this.r) this.position.y = -this.r;
}
// Separation
// Method checks for nearby boids and steers away
separate(boids) {
let desiredSeparation = 25;
let steer = createVector(0, 0);
let count = 0;
// For every boid in the system, check if it's too close
for (let i = 0; i < boids.length; i++) {
let d = p5.Vector.dist(this.position, boids[i].position);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if (d > 0 && d < desiredSeparation) {
// Calculate vector pointing away from neighbor
let diff = p5.Vector.sub(this.position, boids[i].position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
// Average -- divide by how many
if (count > 0) {
steer.div(count);
}
// As long as the vector is greater than 0
if (steer.mag() > 0) {
// Implement Reynolds: Steering = Desired - Velocity
steer.normalize();
steer.mult(this.maxspeed);
steer.sub(this.velocity);
steer.limit(this.maxforce);
}
return steer;
}
// 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); // Start with empty vector to accumulate all locations
let count = 0;
for (let i = 0; i < boids.length; i++) {
let d = p5.Vector.dist(this.position, boids[i].position);
if (d > 0 && d < neighborDistance) {
sum.add(boids[i].position); // Add location
count++;
}
}
if (count > 0) {
sum.div(count);
return this.seek(sum); // Steer towards the location
} else {
return createVector(0, 0);
}
}
}