Python code here.
# From Prof. Claudio Esperança examples for BrythonIDE
# https://github.com/esperanc/brythonide/blob/master/demoSketches/boids.py
boids = [];
def setup() :
createCanvas(720, 400);
# Add an initial set of boids into the system
for i in range(40):
boids.append (Boid(random(720), random(400)))
def draw() :
background(51);
# Run all the boids
for boid in boids: boid.run(boids)
# Boid class
# Methods for Separation, Cohesion, Alignment added
class Boid (object):
def __init__(self, x, y) :
self.acceleration = createVector(0, 0);
self.velocity = p5.Vector.random2D();
self.position = createVector(x, y);
self.r = 3.0;
self.maxspeed = 3; # Maximum speed
self.maxforce = 0.05; # Maximum steering force
def run (self, boids):
self.flock(boids);
self.update();
self.borders();
self.render();
# Forces go into acceleration
def applyForce (self,force):
self.acceleration.add(force);
# We accumulate a new acceleration each time based on three rules
def flock (self, boids) :
sep = self.separate(boids); # Separation
ali = self.align(boids); # Alignment
coh = self.cohesion(boids); # Cohesion
# Arbitrarily weight these forces
sep.mult(2.5);
ali.mult(1.0);
coh.mult(1.0);
# Add the force vectors to acceleration
self.applyForce(sep);
self.applyForce(ali);
self.applyForce(coh);
# Method to update location
def update (self) :
# Update velocity
self.velocity.add(self.acceleration);
# Limit speed
self.velocity.limit(self.maxspeed);
self.position.add(self.velocity);
# Reset acceleration to 0 each cycle
self.acceleration.mult(0);
# A method that calculates and applies a steering force towards a target
# STEER = DESIRED MINUS VELOCITY
def seek (self,target):
desired = p5.Vector.sub(target, self.position); # A vector pointing from the location to the target
# Normalize desired and scale to maximum speed
desired.normalize();
desired.mult(self.maxspeed);
# Steering = Desired minus Velocity
steer = p5.Vector.sub(desired, self.velocity);
steer.limit(self.maxforce); # Limit to maximum steering force
return steer;
# Draw boid as a circle
def render (self) :
fill(127, 127);
stroke(200);
ellipse(self.position.x, self.position.y, 16, 16);
# Wraparound
def borders (self) :
if (self.position.x < -self.r): self.position.x = width + self.r;
if (self.position.y < -self.r): self.position.y = height + self.r;
if (self.position.x > width + self.r): self.position.x = -self.r;
if (self.position.y > height + self.r): self.position.y = -self.r;
# Separation
# Method checks for nearby boids and steers away
def separate (self, boids) :
desiredseparation = 25.0;
steer = createVector(0, 0);
count = 0;
# For every boid in the system, check if it's too close
for i in range(len(boids)):
d = p5.Vector.dist(self.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) and (d < desiredseparation)) :
# Calculate vector pointing away from neighbor
diff = p5.Vector.sub(self.position, boids[i].position);
diff.normalize();
diff.div(d); # Weight by distance
steer.add(diff);
count+=1; # 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(self.maxspeed);
steer.sub(self.velocity);
steer.limit(self.maxforce);
return steer;
# Alignment
# For every nearby boid in the system, calculate the average velocity
def align (self, boids) :
neighbordist = 50;
sum = createVector(0, 0);
count = 0;
for i in range(len(boids)):
d = p5.Vector.dist(self.position, boids[i].position);
if ((d > 0) and (d < neighbordist)) :
sum.add(boids[i].velocity);
count+=1;
if (count > 0) :
sum.div(count);
sum.normalize();
sum.mult(self.maxspeed);
steer = p5.Vector.sub(sum, self.velocity);
steer.limit(self.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
def cohesion (self, boids) :
neighbordist = 50;
sum = createVector(0, 0); # Start with empty vector to accumulate all locations
count = 0;
for i in range(len(boids)):
d = p5.Vector.dist(self.position, boids[i].position);
if ((d > 0) and (d < neighbordist)) :
sum.add(boids[i].position); # Add location
count+=1;
if (count > 0) :
sum.div(count);
return self.seek(sum); # Steer towards the location
else:
return createVector(0, 0);