Public
Edited
Jul 27, 2023
Insert cell
Insert cell
container = container_from(canvas);
Insert cell
sketch = function( p ) {
// Adapted from The Nature of Code by Daniel Shiffman
// http://natureofcode.com

// craig reynolds, steering behaviors

let flock;
let cohesionSlider;
let separationSlider;
let alignmentSlider;

p.setup = function() {
p.createCanvas(p.windowWidth, 800);
cohesionSlider = p.createSlider(0, 1, 1, 0.1).position(100,10);
separationSlider = p.createSlider(0, 10, 1, 1).position(100,30);
alignmentSlider = p.createSlider(0, 2, 1, 0.1).position(100,50);
flock = new Flock();
// Add an initial set of boids into the system
for (let i = 0; i < 50; i++) {
let b = new Boid(p.width/2, p.height/2);
flock.addBoid(b);
}
}

p.draw = function() {
p.background(0, 1);
flock.run();
p.fill(255);
p.noStroke();
p.text('cohesion', 20, 20);
p.text('separation', 20, 40);
p.text('alignment', 20, 60);
}
//-----------------------------------------

class Flock {
constructor() {
// An array for all the boids
this.boids = []; // Initialize the array
}
run() {
for (let i = 0; i < this.boids.length; i++) {
// Passing entire list of boids to each boid individually
this.boids[i].run(this.boids);
}
}
addBoid(b) {
this.boids.push(b);
}
}

//-----------------------------------------
class Boid {
constructor(x, y) {
this.acceleration = p.createVector(0, 0);
this.velocity = p.createVector(p.random(-1, 1), p.random(-1, 1));
this.position = p.createVector(x, y);
this.r = 20.0;
this.maxspeed = 8; // Maximum speed
this.maxforce = 0.05; // Maximum steering force
}
run(boids) {
this.flock(boids);
this.update();
this.borders();
this.render();
}
applyForce(F) {
// We could add mass here if we want A = F / M
this.acceleration.add(F);
}
//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.cohesion(boids); // Cohesion
// arbitrarily weight these forces
sep.mult(separationSlider.value());
ali.mult(alignmentSlider.value());
coh.mult(cohesionSlider.value());
// add the force vectors to acceleration
this.applyForce(sep);
this.applyForce(ali);
this.applyForce(coh);
}
//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) {
// A vector pointing from the location to the target
let desired = p5.Vector.sub(target, this.position);
// 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;
}
render() {
// Draw a triangle rotated in the direction of velocity
let theta = this.velocity.heading() + p.radians(90);
let hue = p.round(180 + p.cos(p.frameCount*0.001) * 180);
let c = p.color(`hsl(${hue}, 100%, 50%)`);
p.noFill();
p.stroke(c);
p.push();
p.translate(this.position.x, this.position.y);
p.rotate(theta);
p.beginShape();
p.vertex(0, -this.r * 2);
p.vertex(-this.r, this.r * 2);
p.vertex(this.r, this.r * 2);
p.endShape(p.CLOSE);
p.pop();
}
//wrap around
borders(boids) {
if (this.position.x < -this.r) this.position.x = p.width + this.r;
if (this.position.y < -this.r) this.position.y = p.height + this.r;
if (this.position.x > p.width + this.r) this.position.x = -this.r;
if (this.position.y > p.height + this.r) this.position.y = -this.r;
}
// Separation
// Method checks for nearby boids and steers away
separate(boids) {
let desiredseparation = 25.0;
let steer = p.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;
}
// Alignment
// For every nearby boid in the system, calculate the average velocity
align(boids) {
let neighbordist = 50;
let sum = p.createVector(0, 0);
let count = 0;
for (let i = 0; i < boids.length; i++) {
var d = p5.Vector.dist(this.position, boids[i].position);
if ((d > 0) && (d < neighbordist)) {
sum.add(boids[i].velocity);
count++;
}
}
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(this.maxspeed);
var steer = p5.Vector.sub(sum, this.velocity);
steer.limit(this.maxforce);
return steer;
} else {
return p.createVector(0, 0);
}
}
// Cohesion
// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
cohesion(boids) {
let neighbordist = 50;
let sum = p.createVector(0, 0); // Start with empty vector to accumulate all locations
let count = 0;
for (var i = 0; i < boids.length; i++) {
let d = p5.Vector.dist(this.position, boids[i].position);
if ((d > 0) && (d < neighbordist)) {
sum.add(boids[i].position); // Add location
count++;
}
}
if (count > 0) {
sum.div(count);
return this.seek(sum); // Steer towards the location
} else {
return p.createVector(0, 0);
}
}
}
}



Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more