class Boid { private PVector position, velocity; public Boid(PVector initialPosition, PVector initialVelocity) { position = initialPosition; velocity = initialVelocity; } // Executes the rules or behaviors of the boids algorithm private void behaviours(ArrayList boids) { PVector flockVector = new PVector(0,0,0); PVector distanceVector = new PVector(0,0,0); PVector accelerationVector = new PVector(0,0,0); flockVector = flock(this.position, boids); distanceVector = distance(this.position, boids); accelerationVector = acceleration(this.velocity, boids); this.velocity.add(flockVector); this.velocity.add(distanceVector); this.velocity.add(accelerationVector); limitSpeed(this.velocity, boids); this.position.add(this.velocity); keepOnScreen(); } // Brings the calculated data to life private void drawFlock() { float velocityAngle = this.velocity.heading2D() + radians(90); pushMatrix(); translate(this.position.x, this.position.y); rotate(velocityAngle); beginShape(TRIANGLES); vertex(0, -10.0); vertex(-2.5, 10.0); vertex(2.5, 10.0); endShape(); popMatrix(); } // The most important aspect to the flocking algorithm; steers the current boid towards the centre of mass of all surrounding boids private PVector flock(PVector originalBoidPosition, ArrayList boids) { PVector flockPositions = new PVector(0,0,0); PVector currentBoidPosition = new PVector(0,0,0); for (int i = 0; i < boids.size(); i++) { Boid tmpBoid = (Boid) boids.get(i); flockPositions = tmpBoid.position; if (flockPositions != originalBoidPosition) { currentBoidPosition.add(flockPositions); } } currentBoidPosition.div(float(boids.size() - 1)); currentBoidPosition.sub(originalBoidPosition); currentBoidPosition.div(100.0f); return currentBoidPosition; } // Keeps the boids from flocking on top of each other by setting a minimum proximity boundary private PVector distance(PVector originalBoidPosition, ArrayList boids) { PVector flockPositions = new PVector(0,0,0); PVector difference = new PVector(0,0,0); PVector distance = new PVector(0,0,0); for (int i = 0; i < boids.size(); i++) { Boid tmpBoid = (Boid) boids.get(i); flockPositions = tmpBoid.position; if (flockPositions != originalBoidPosition) { if (PVector.dist(originalBoidPosition, flockPositions) < 15.0f) { difference = PVector.sub(flockPositions, originalBoidPosition); distance.sub(difference); } } } return distance; } // Calculates the current acceleration for any given boid based on the average acceleration of the combined flock private PVector acceleration(PVector originalBoidVelocity, ArrayList boids) { PVector flockVelocities = new PVector(0,0,0); PVector velocity = new PVector(0,0,0); for (int i = 0; i < boids.size(); i++) { Boid tmpBoid = (Boid) boids.get(i); flockVelocities = tmpBoid.velocity; if (flockVelocities != originalBoidVelocity) { velocity.add(flockVelocities); } } velocity.div(float(boids.size() - 1)); velocity.sub(originalBoidVelocity); velocity.div(4.0f); return velocity; } // Sets a maximum speed private void limitSpeed(PVector originalBoidVelocity, ArrayList boids) { float maxSpeed = 6.0f; PVector flockVelocities = new PVector(0,0,0); PVector adjustedVelocity = new PVector(0,0,0); for (int i = 0; i < boids.size(); i++) { Boid tmpBoid = (Boid) boids.get(i); flockVelocities = tmpBoid.velocity; if (abs(originalBoidVelocity.mag()) > maxSpeed) { this.velocity.normalize(); this.velocity.mult(maxSpeed); } } } // Keeps the boids from moving outside of the windows boundaries private void keepOnScreen() { if (this.position.x < 0) { this.position.x += 15; } else if (this.position.x > width) { this.position.x -= 15.0f; } if (this.position.y < 0) { this.position.y += 15; } else if (this.position.y > height) { this.position.y -= 15; } } }