class Vec { float x,y; Vec() { x = y = 0; } Vec(float vx, float vy) { x = vx; y = vy; } void add(Vec v) { x+=v.x; y+=v.y; } void sub(Vec v) { x-=v.x; y-=v.y; } void set(Vec v) { x=v.x; y=v.y; } void scale(float s) { x*=s; y*=s; } float length() { return sqrt(sq(x)+sq(y)); } } class Boid { Vec velocity; Vec location; int col; Boid() { location = new Vec(random(-1000,1000)+width*scaleMult/2, random(-1000,1000)+height*scaleMult/2); velocity = new Vec(random(-1000,1000),random(-1000,1000)); col = color(random(200,255),random(180,230),random(50,100)); } void move() { if (velocity.length() > 0.0) { velocity.scale(1500.0 / velocity.length()); } location.add(velocity); } void draw() { noStroke(); fill(col); ellipse(location.x,location.y,650,650); } boolean canSee(Boid b) { // return true; float heading = atan2(velocity.y,velocity.x); Vec toB = new Vec(b.location.x-location.x,b.location.y-location.y); float angleToB = atan2(toB.y,toB.x); if (abs(heading-angleToB) < HALF_PI && toB.length() < 50000) { stroke(255,8); line(location.x,location.y,b.location.x,b.location.y); return true; } else { return false; } } } Boid boids[]; float scaleMult = 250.0; void setup() { size(400,400); boids = new Boid[32]; for (int i = 0; i < boids.length; i++) { boids[i] = new Boid(); } ellipseMode(CENTER_DIAMETER); noStroke(); fill(255); background(80,40,40); framerate(30); } void loop() { if(mousePressed) { fadescr(80,40,40); } else { background(80,40,40); } translate(width/10,height/10); scale(0.8,0.8); scale(1.0/scaleMult); for (int i = 0; i < boids.length; i++) { boids[i].move(); boids[i].draw(); } for (int i = 0; i < boids.length; i++) { boids[i].velocity.add(cohesion(boids[i])); boids[i].velocity.add(separation(boids[i])); boids[i].velocity.add(alignment(boids[i])); boids[i].velocity.add(arena(boids[i])); } } Vec cohesion(Boid b) { Vec cohese = new Vec(); int count = 0; for (int i = 0; i < boids.length; i++) { if(boids[i] != b) { if (b.canSee(boids[i])) { cohese.add(boids[i].location); count++; } } } if (count > 0) { cohese.scale(1.0/(float)count); cohese.sub(b.location); cohese.scale(0.01); } return cohese; } Vec separation(Boid b) { Vec separate = new Vec(); for (int i = 0; i < boids.length; i++) { if(boids[i] != b) { if (b.canSee(boids[i])) { Vec temp = new Vec(); temp.set(boids[i].location); temp.sub(b.location); if (temp.length() < 1500) { separate.sub(temp); } } } } return separate; } Vec alignment(Boid b) { Vec align = new Vec(); int count = 0; for (int i = 0; i < boids.length; i++) { if(boids[i] != b) { if (b.canSee(boids[i])) { align.add(boids[i].velocity); count++; } } } if (count > 0) { align.scale(1.0 / (float)count); align.sub(b.velocity); align.scale(0.125); } return align; } Vec arena(Boid b) { Vec arena = new Vec(); if (b.location.x < 0) { arena.add(new Vec(200,0)); } else if (b.location.x > width*scaleMult) { arena.add(new Vec(-200,0)); } if (b.location.y < 0) { arena.add(new Vec(0,200)); } else if (b.location.y > height*scaleMult) { arena.add(new Vec(0,-200)); } return arena; } void fadescr(int r, int g, int b) { int red, green, blue; for (int i = 0; i < pixels.length; i++) { red = (pixels[i] >> 16) & 0x000000ff; green = (pixels[i] >> 8) & 0x000000ff; blue = pixels[i] & 0x000000ff; pixels[i] = (((red+((r-red)>>3)) << 16) | ((green+((g-green)>>3)) << 8) | (blue+((b-blue)>>3))); } }