int NUM_CHASERS = 1024; float SWARM_ALPHA = 130.0; float BOX_ALPHA = 40.0; float BACKGROUND_ALPHA = 240.0; class Chaser { Vec3f pos, vel, target, heading; float speed; color col; public Chaser() { pos = new Vec3f(random(width),random(height),random(-depth,0.0)); vel = new Vec3f(); target = new Vec3f(pos); heading = new Vec3f(random(250.0),random(250.0),random(250.0)); speed = random(depth/30,depth/80); // fun to change these col = color(random(210,230),random(190,210),140,SWARM_ALPHA); } public void move() { heading.scale(depth); heading.add((target.x - pos.x)*0.04, (target.y - pos.y)*0.04, (target.z - pos.z)*0.04); heading.add((averageLoc.x - pos.x)*0.56, (averageLoc.y - pos.y)*0.56, (averageLoc.z - pos.z)*0.56); heading.add(-(averageLoc.x - (pos.x*invChaserLength))*0.1, -(averageLoc.y - (pos.y*invChaserLength))*0.1, -(averageLoc.z - (pos.z*invChaserLength))*0.1); heading.add((averageHead.x)*0.0333, (averageHead.y)*0.0333, (averageHead.z)*0.0333); heading.add((lastTargetX - pos.x)*0.667, (lastTargetY - pos.y)*0.667, (lastTargetZ - pos.z)*0.667); heading.scale(speed/heading.length()); vel.set(heading.x,heading.y,heading.z); pos.add(vel); target.add(random(-10,10),random(-10,10),random(-10,10)); target.set(max(0,target.x),max(0,target.y),min(0,target.z)); target.set(min(width,target.x),min(height,target.y),max(-depth,target.z)); pos.set(max(0,pos.x),max(0,pos.y),min(0,pos.z)); pos.set(min(width,pos.x),min(height,pos.y),max(-depth,pos.z)); } public void draw() { push(); translate(pos.x,pos.y,pos.z); stroke(0,0,0,SWARM_ALPHA); point(0,0,0); //point(-heading.x,-heading.y,-heading.z); stroke(col); line(0,0,0,-heading.x,-heading.y,-heading.z); pop(); } } Chaser[] chasers; float depth = 0; Vec3f averageLoc = new Vec3f(); Vec3f averageHead = new Vec3f(); float targetX, targetY, targetZ, lastTargetX, lastTargetY, lastTargetZ; float invChaserLength = 0.0; float angle = 0.0; void setup() { hint(NEW_GRAPHICS); size(360,360); //lights(); depth = (width + height) / 2; chasers = new Chaser[NUM_CHASERS]; for (int i = 0; i < chasers.length; i++) { chasers[i] = new Chaser(); } invChaserLength = 1.0/(float)chasers.length; targetX = (width/2); targetY = (height/2); targetZ = (-depth/2); lastTargetX = targetX; lastTargetY = targetY; lastTargetZ = targetZ; } void loop() { background(255); //for (int i = 0; i < g.zbuffer.length; i++) { // g.zbuffer[i] = MAX_FLOAT; //} //fill(245,245,255,BACKGROUND_ALPHA); //rect(-1,-1,width+2,height+2); translate(width*0.1,height*0.1,-depth*0.1); scale(0.8); translate(width*0.5,height*0.5,-depth*0.5); rotateX(0.3*angle); rotateY(angle); rotateZ(0.2*angle); stroke(200,200,200,BOX_ALPHA); noFill(); box(width,height,depth); translate(-width*0.5,-height*0.5,(depth*0.5)); averageLoc.set(0.0f,0.0f,0.0f); averageHead.set(0.0f,0.0f,0.0f); for (int i = 0; i < chasers.length; i++) { averageLoc.add(chasers[i].pos); averageHead.add(chasers[i].heading); } averageLoc.scale(invChaserLength); averageHead.scale(invChaserLength); for (int i = 0; i < chasers.length; i++) { if (!mousePressed) { chasers[i].move(); } chasers[i].draw(); } if (!mousePressed) { lastTargetX += (targetX-lastTargetX)*0.04; lastTargetY += (targetY-lastTargetY)*0.04; lastTargetZ += (targetZ-lastTargetZ)*0.04; if (abs(averageLoc.x - targetX) < 10.0 && abs(averageLoc.y - targetY) < 10.0 || random(1.0) < 0.05) { float choice = random(1.0); if (choice < 0.333333333) { targetX = (width/10) * int(random(2,8) + 0.5); } else if (choice < 0.666666667) { targetY = (height/10) * int(random(2,8) + 0.5); } else { targetZ = (-depth/10) * int(random(2,8) + 0.5); } } } stroke(255,225,225,BOX_ALPHA); push(); translate(lastTargetX,lastTargetY,-depth/2); box(1.0,1.0,depth); pop(); push(); translate(width/2,lastTargetY,lastTargetZ); box(width,1.0,1.0); pop(); push(); translate(lastTargetX,height/2,lastTargetZ); box(1.0,height,1.0); pop(); if (mousePressed) { angle += 0.025; } else { angle += -angle * 0.01; } } void keyPressed() { for (int i = 0; i < chasers.length; i++) { //chasers[i].pos = new Vec3f(lastTargetX,lastTargetY,lastTargetZ); chasers[i].heading = new Vec3f(lastTargetX-chasers[i].pos.x,lastTargetY-chasers[i].pos.y,lastTargetZ-chasers[i].pos.z); //chasers[i].target = new Vec3f(chasers[i].pos); //chasers[i].vel = new Vec3f(); //random(width),random(height),random(-depth,0)); // new Vec3f(width/2,height/2,-depth/2); } } class Vec3f { public float x,y,z; public Vec3f() { this(0.0f,0.0f,0.0f); } public Vec3f(Vec3f other) { this(other.x,other.y,other.z); } public Vec3f(float x,float y,float z) { this.x=x; this.y=y; this.z=z; } void set(float x,float y,float z) { this.x=x; this.y=y; this.z=z; } void add(float x,float y,float z) { this.x+=x; this.y+=y; this.z+=z; } void add(Vec3f other) { this.x+=other.x; this.y+=other.y; this.z+=other.z; } void sub(float x,float y,float z) { this.x-=x; this.y-=y; this.z-=z; } void scale(float s) { this.x*=s; this.y*=s; this.z*=s; } Vec3f cross(Vec3f other) { return new Vec3f((this.y*other.z)-(this.z*other.y),(this.x*other.z)-(this.z*other.x),(this.x*other.y)-(this.y*other.x)); } float length() { return sqrt((x*x)+(y*y)+(z*z)); } }