I added some element of “steering” to a previous sketch to create a group of sea creatures or boids that move through the screen. The three forces applied to each boid to create the steering behavior are avoid, approach, and align.
Processing code:
ArrayList boids = new ArrayList();
int boidNum = 15; // amount of boids
float timer;
color[] colors = new color[3];
void setup() {
frameRate(30);
size(700, 700);
colors[0] =color(240,110,110, 150); // pink
colors[1] = color(250,190,120, 140); // yellow
colors[2] = color(160,80,100, 150); // purple
for (int i=0; i boids) {
avoidForce(boids);
approachForce(boids);
alignForce(boids);
}
void update() {
vel.add(acc);
loc.add(vel);
acc.mult(0);
vel.limit(5);
// Check edges
if (loc.x<=0) {
loc.x = width;
}
if (loc.x>width) {
loc.x = 0;
}
if (loc.y<=0) {
loc.y = height;
}
if (loc.y>height) {
loc.y = 0;
}
}
void applyF(PVector force) {
//F=ma
force.div(mass);
acc.add(force);
}
void display() {
update();
fill(cl);
noStroke();
ellipse(loc.x, loc.y, mass, mass);
ellipse(loc.x, loc.y, mass*.8, mass*.8);
float theta = vel.heading2D();
// LEGS
pushMatrix();
translate(loc.x, loc.y);
rotate(theta);
stroke(cl);
strokeWeight(5);
displayLeg(mass * 0.75, 0.75, 0.3);
displayLeg(mass * 0.75, 0.25, 0.1);
displayLeg(mass * 0.75, 0.25, 0.1);
displayLeg(mass * 0.75, 0.75, 0.3);
popMatrix();
}
void displayLeg(float length, float angle, float delay) {
float rotation = 0.5 * sin(3 * (timer  delay));
float leftAngle = angle + rotation;
float rightAngle = PI  angle  rotation;
line(0, 0, length * sin(leftAngle), length * cos(leftAngle));
line(0, 0, length * sin(rightAngle), length * cos(rightAngle));
}
// AVOID
void avoidForce(ArrayList boids) {
float count = 0; // how many boids are close
PVector locSum = new PVector(); // store positions
for (Boid other : boids) {
int separation = mass + 60; // separation, using mass as reference
PVector dist = PVector.sub(other.getLoc(), loc); //distance to other boid
float d = dist.mag();
if (d != 0 && d0) {
locSum.div(count);
PVector avoidVec = PVector.sub(loc, locSum);
avoidVec.limit(maxForce*3);
applyF(avoidVec);
}
}
// APPROACH
void approachForce(ArrayList boids) {
float count = 0; // keep track of boids
PVector locSum = new PVector();
for (Boid other : boids) {
int approachRadius = mass + 60;
PVector dist = PVector.sub(other.getLoc(), loc);
float d = dist.mag();
if (d != 0 && d0) {
locSum.div(count);
PVector approachVec = PVector.sub(locSum, loc);
approachVec.limit(maxForce);
applyF(approachVec);
}
}
// ALIGN
void alignForce(ArrayList boids) {
float count = 0; // keep track of how many boids are in sight.
PVector velSum = new PVector(); // store vels of boids in sight.
for (Boid other : boids) {
int alignRadius = mass + 100;
PVector dist = PVector.sub(other.getLoc(), loc);
float d = dist.mag();
if (d != 0 && d0) {
velSum.div(count);
PVector alignVec = velSum;
alignVec.limit(maxForce);
applyF(alignVec);
}
}
PVector getLoc() {
return loc;
}
PVector getVel() {
return vel;
}
}
