Hi all, first post!
So this is my first big stab at boids. It’s still kinda wonky - I plan to implement more features and corrections. I’m more looking for any general tips to increase efficiency (I’m not sure if it’s just my computer’s lack of a graphics card but it can be rather laggy.)
I’d be open to any feedback on my methodology or more general tips. I’m basically just teaching myself right now so I don’t really know what I’m doing.
Thanks!
Bird [] birds;
PVector sum, nextP, avgHead, avgLoc, avgLocDirection, avgHeadUnit;
int a, b, count, size, bIndicator;
boolean loop;
float speed, augAvgHeading, augAvgLoc, maxAug, incrAug,
finalDir, augSplit, avoidDir, avoidLERP, PS, check, closest;
int target, num;
color BG;
void setup() {
colorMode(RGB, 255, 255, 255);
fullScreen();
smooth();
BG = color(240, 230, 230);
//strokeWeight(4);
frameRate(30);
loop = true;
num = 500; //num birds
avgLoc = new PVector(0, 0);
avgHead = new PVector(0, 0);
avgHeadUnit = new PVector(0, 0);
augSplit = 0.75; //for lerp: lower weights towards avgLoc, higher towards avgHeading
maxAug = 0.1; //augmentation increment (& limit) to each bird's velocity heading, for each round of loop
PS = 25; //personal space of each bird
size = 2;
avoidLERP = 0.8; //how much a bird alters its course based on proximity
noStroke();
birds = new Bird [num];
for (int c = 0; c < num; c++) {
birds[c] = new Bird();
}
}
void draw() {
avgHead.set(0, 0);
avgLoc.set(0, 0);
textSize(25);
fill(0);
stroke(0);
background(BG);
for (int c = 0; c < num; c++) //gets heading and location values from each 'bird'
{
avgHead.add(birds[c].unitVector()); //vector sum of every bird's heading
}
if (mousePressed)
{
avgLoc.set(mouseX, mouseY);
} else {
for (int c = 0; c < num; c++) //gets heading and location values from each 'bird'
{
avgLoc.add(birds[c].loc);
}
avgLoc.div(num);
}
//avgLoc pointer
stroke(150, 0, 0);
ellipse(avgLoc.x, avgLoc.y, size, size);
for (int c = 0; c < num; c++) //calculate angle-augmentation (rotation) for each bird
{
incrAug=maxAug;
fill(0);
avgLocDirection = PVector.sub(avgLoc, birds[c].loc);
finalDir = ( ( avgHead.heading() - avgLocDirection.heading() + 3*PI ) % TWO_PI ) - PI; //determines range between two headings
// weighted average : LERP method
finalDir = lerp(0, finalDir, augSplit);
finalDir = ((avgLocDirection.heading() + finalDir ) % TWO_PI ) ; //determines final resting place of aspired direction
finalDir = (( finalDir - birds[c].vel.heading() + 3*PI ) % TWO_PI ) - PI; //determines finalAug
closest = PS;
bIndicator = num+1;
for (int d = num-1; d >= 0; d--) //check and adjust for bird-bird proximity
{
if (c != d) {
check = PVector.dist(birds[c].loc, birds[d].loc);
}
if (check < PS) {
if (check < closest)
{
closest = check;
bIndicator = d;
}
}
}
if (bIndicator != num+1)
{
avoidDir = (((PVector.sub(birds[c].loc, birds[bIndicator].loc)).heading() - birds[c].vel.heading() + 3*PI ) % TWO_PI ) - PI;
finalDir = lerp(finalDir, avoidDir, avoidLERP);
}
if (incrAug >= abs(finalDir)) //smooths motion a little
{
birds[c].vel.rotate(finalDir);
} else {
incrAug = (finalDir / abs(finalDir)) * incrAug;
birds[c].vel.rotate(incrAug);
}
birds[c].updateLoc();
if (bIndicator != num+1) {
fill( 0, 0, lerp(0, 255, -closest/PS+1.5)); //bird turns blue when close to others
}
ellipse(birds[c].loc.x, birds[c].loc.y, size, size);
}
}
//-----------//
void keyReleased() {
noLoop();
loop = false;
}
class Bird {
PVector loc, vel, unit;
float speed = 12;
Bird() {
loc = new PVector(int(random(width)), int(random(height)));
vel = new PVector(speed, 0);
vel.rotate(random(-PI, PI)); //this is just how heading() describes angles
unit = new PVector();
unit = unitVector();
}
PVector unitVector() {
unit = vel.copy();
unit.normalize();
return unit;
}
void updateLoc() {
loc.add(vel);
}
}