xxxxxxxxxx
140
let vehicles = [];
function setup() {
createCanvas(800, 600);
for (let i = 0; i < 100; i++) {
vehicles.push(new Vehicle(random(width), random(height)));
}
}
function draw() {
background(220);
vehicles.forEach(vehicle => {
vehicle.flock(vehicles); // Flocking behavior
vehicle.wander(); // Adds Perlin noise-based wandering
vehicle.update();
vehicle.display();
});
}
class Vehicle {
constructor(x, y) {
this.position = createVector(x, y);
this.velocity = p5.Vector.random2D();
this.acceleration = createVector();
this.maxSpeed = random(2, 4);
this.maxForce = 0.1;
this.noiseOffset = random(1000); // Offset for Perlin noise
}
// Main flocking behavior function
flock(vehicles) {
let cohesion = this.cohesion(vehicles);
let separation = this.separation(vehicles);
let alignment = this.alignment(vehicles);
// Adjusting strength of each behavior
cohesion.mult(0.5);
separation.mult(0.5);
alignment.mult(1.0);
this.applyForce(cohesion);
this.applyForce(separation);
this.applyForce(alignment);
}
// Cohesion: Steer towards average position of local flockmates
cohesion(vehicles) {
let perceptionRadius = 50;
let steering = createVector();
let total = 0;
vehicles.forEach(other => {
let d = dist(this.position.x, this.position.y, other.position.x, other.position.y);
if (other != this && d < perceptionRadius) {
steering.add(other.position); // Add position of each neighbor
total++;
}
});
if (total > 0) {
steering.div(total); // Get average position
steering.sub(this.position); // Steering = desired - current
steering.setMag(this.maxSpeed);
steering.sub(this.velocity);
steering.limit(this.maxForce);
}
return steering;
}
// Separation: Steer away from close flockmates
separation(vehicles) {
let perceptionRadius = 25;
let steering = createVector();
let total = 0;
vehicles.forEach(other => {
let d = dist(this.position.x, this.position.y, other.position.x, other.position.y);
if (other != this && d < perceptionRadius) {
let diff = p5.Vector.sub(this.position, other.position);
diff.div(d * d); // Weight by distance (closer = stronger force)
steering.add(diff);
total++;
}
});
if (total > 0) {
steering.div(total);
steering.setMag(this.maxSpeed);
steering.sub(this.velocity);
steering.limit(this.maxForce);
}
return steering;
}
// Alignment: Steer towards average velocity of local flockmates
alignment(vehicles) {
let perceptionRadius = 50;
let steering = createVector();
let total = 0;
vehicles.forEach(other => {
let d = dist(this.position.x, this.position.y, other.position.x, other.position.y);
if (other != this && d < perceptionRadius) {
steering.add(other.velocity);
total++;
}
});
if (total > 0) {
steering.div(total);
steering.setMag(this.maxSpeed);
steering.sub(this.velocity);
steering.limit(this.maxForce);
}
return steering;
}
// Wander behavior using Perlin noise for more organic movement
wander() {
let wanderTheta = noise(this.noiseOffset) * TWO_PI * 2; // Perlin noise-based angle
this.noiseOffset += 0.01; // Move noise offset
let wanderForce = p5.Vector.fromAngle(wanderTheta);
wanderForce.setMag(0.1);
this.applyForce(wanderForce);
}
applyForce(force) {
this.acceleration.add(force);
}
update() {
this.velocity.add(this.acceleration);
this.velocity.limit(this.maxSpeed);
this.position.add(this.velocity);
this.acceleration.mult(0);
}
display() {
stroke(0);
fill(127);
ellipse(this.position.x, this.position.y, 16, 16);
}
}