import java.util.*; private static float DIST = 75; private int N = 0; private static final float BORDER_TENTION = .5; private static final int SPEED_LIMIT = 2; private static final int VISIBILITY = 1500; private static final int CROWDING = 15; private static final int TAIL = 25; int toAdd = 0; ArrayList gnats; ArrayList newBorns; //boolean showTitle = false; boolean pause = false; boolean scatter = false; boolean treatAsBoids = true; boolean followMouse = false; void setup(){ size(480, 360); smooth(); noStroke(); frameRate(30); newBorns = new ArrayList(); gnats = new ArrayList(); for(int i = 0; i < N; i++){ gnats.add(new Boid()); } } void draw(){ if(pause) return; fill(255, TAIL ); rect(0, 0, width, height); for(int i = 0; i < newBorns.size(); i++){ gnats.add(0, newBorns.get(i)); } newBorns.clear(); fill(0); for(int i = 0; i < gnats.size(); i++){ Boid next = (Boid)gnats.get(i); if(treatAsBoids){ next.updateAsBoid(); }else{ next.updateAsGnat(); } ellipse(next.x, next.y, 5, 5); } } private class Boid{ public float velx; public float vely; public float x; public float y; public Boid(){ this(random(width), random(height)); } public Boid(float x, float y){ this.x = x; this.y = y; } public Boid(Boid b){ this(b.x + random(3), b.y + random(3)); this.velx = b.velx; this.vely = b.vely; } public void updateAsGnat(){ Boid closest = null; float distance = 0; for(int i = 0; i < gnats.size(); i++){ Boid next = (Boid)gnats.get(i); if(next != this){ float d = dist(next.x, next.y, this.x, this.y); if(closest == null || abs(DIST - d) < distance){ closest = next; distance = d; } } } int mult = distance > DIST ? 1 : -1; this.velx += (closest.x - this.x)/4 * mult; this.vely += (closest.y - this.y)/4 * mult; update(); } public void updateAsBoid(){ int found = 0; float x1,x2,x3, x4, x5, y1, y2, y3, y4, y5; x1 = x2 = x3 = x4 = x5 = y1 = y2 = y3 = y4 = y5 = 0; for(int i = 0; i < gnats.size(); i++){ Boid b = (Boid)gnats.get(i); float distance = dist(this.x, this.y, b.x, b.y); if(this != b && distance < VISIBILITY){ found++; x1 += b.x; y1 += b.y; //Rule 2 if(distance < CROWDING){ x2 = (this.x - b.x); y2 = (this.y - b.y); } //Rule3 x3 += b.velx; y3 += b.vely; } } if(found > 0){ x1 /= (found); y1 /= (found); x3 /= found; y3 /= found; } x1 = (x1 - this.x)/100; y1 = (y1 - this.y)/100; x3 = (x3 - this.velx)/8; y3 = (y3 - this.vely)/8; //correct border problems if(this.x < 100){ x4 = BORDER_TENTION; }else if(this.x > width - 100){ x4 = -BORDER_TENTION; } if(this.y < 100){ y4 = BORDER_TENTION; }else if(this.y > height - 100){ y4 = -BORDER_TENTION; } if(followMouse && dist(mouseX, mouseY, this.x, this.y) < VISIBILITY){ x5 = (mouseX - this.x)/40; y5 = (mouseY - this.y)/40; } //println( x1 + " " + x2+ " " + x3+ " " + x4 + " "+ x5); //calculate and update if(scatter){ x1 = -x1; y1 = -y1; } this.velx += x1 + x2 + x3 + x4 + x5; this.vely += y1 + y2 + y3 + y4 + y5; update(); } //limit speed void update(){ float m = mag(this.velx, this.vely); if(m > SPEED_LIMIT){ this.velx = this.velx / m * SPEED_LIMIT; this.vely = this.vely / m * SPEED_LIMIT; } this.x += this.velx; this.y += this.vely; } } void mousePressed(){ newBorns.add(new Boid(mouseX, mouseY)); } void keyPressed(){ if(key == 's'){ scatter = !scatter; }else if(key == 'm'){ followMouse = !followMouse; }else if(key == 'f'){ treatAsBoids = !treatAsBoids; }else if(key == 'd'){ if(gnats.size() > 0){ newBorns.add(new Boid((Boid)gnats.get((int)(Math.random()*gnats.size())))); } }else if(key == 'p'){ pause = !pause; }else if(key == 'c'){ gnats.clear(); } }