float arot; int maxpennies=150; int npennies; float[][] pennies; int maxacc=150; int naccreted = 0; float[] accreta; boolean mouseHeld; float stepsize; int ballsize = 5; int nsides = 16; int nlevels = 25; int lastTime = 0; float[] level; boolean IncludeCone= true; boolean IncludeWalls = false; boolean IncludeFlats = false; boolean UseColor = false; boolean UseLight = false; boolean UseWireFrame = true; boolean RotateFunnel= false; void setup() { size(400, 400, P3D); arot = 0; npennies = 0; pennies = new float[2][maxpennies]; naccreted = 0; accreta = new float[maxacc]; mouseHeld = false; stepsize = TWO_PI/200; level = new float[nlevels]; for (int i = 0; i< nlevels;i++) { level[i] = (nlevels-i)*(nlevels-i)*180.0/(nlevels*nlevels); } colorMode(RGB, 1); } void draw() { int currentTime = millis(); if (currentTime > lastTime+50) { background(0); if (UseLight) lights(); //draw "mouse position bar" noFill(); stroke(0.4,0.4,0.4); rect(width/2-level[0],9*height/10,2*level[0],2); noFill(); stroke(0.4,0.4,0.4); rect(mouseX-ballsize/4,9*height/10-2*ballsize,ballsize/2,3*ballsize); triangle(mouseX,9*height/10-3*ballsize,mouseX-ballsize,9*height/10-2*ballsize,mouseX+ballsize,9*height/10-2*ballsize); noStroke(); fill(1,0,1); ellipse(mouseX,9*height/10,2*ballsize,2*ballsize); //draw "reset button" noFill(); stroke(0.4,0.4,0.4); rect(width/40,height/40,width/20,height/20); line(width/40,height/40,3*width/40,3*height/40); line(3*width/40,height/40,width/40,3*height/40); translate(width / 2, height / 2); rotateY(PI/2); rotateZ(map(mouseY, 0, height, 0, -PI/2)); noStroke(); fill(255, 255, 255); translate(0, -40, 0); arot += stepsize; if (RotateFunnel) { for (int i=0;i TWO_PI) { pennies[1][i] -= TWO_PI; } } for (int i=0;i width/2) { pennies[1][npennies] = PI/2; } else { pennies[1][npennies] = 3*PI/2; } println(mouseX + " " + mouseY + " = " + pennies[0][npennies]+ " " + pennies[1][npennies] ); pushMatrix(); drawPenny(npennies,10); popMatrix(); // sort pennies by radius sortPennies(); npennies++; //if the mouse click was in the reset button area if (mouseX > width/40 && mouseY > height/40 && mouseX < 3*width/40 && mouseY < 3*height/40) { npennies = 0; naccreted = 0; } } if (mousePressed) { mouseHeld= true; } else { mouseHeld = false; } detectCollisions(); lastTime = currentTime; } } float myCurve(float radius) { return height/3 - 10*(sqrt(radius)); } float mySpeed(float r) // angular velocity; go with Keplerian version { return 2000/sqrt(r*r*r); } void drawAccreta(int i) { translate(0,accreta[i],0); fill(1,1,0); noStroke(); sphere(5); } void drawPenny(int i) { translate(pennies[0][i]*cos(pennies[1][i]), myCurve(pennies[0][i]), pennies[0][i]*sin(pennies[1][i])); fill(1,0,1); noStroke(); sphere(5); } void drawPenny(int i,int size) { translate(pennies[0][i]*cos(pennies[1][i]), myCurve(pennies[0][i]), pennies[0][i]*sin(pennies[1][i])); fill(1,0,1); noStroke(); sphere(size); } void sortPennies() { if (npennies<=0) return; float tmp; boolean swapped = true; while (swapped) { swapped = false; for (int i=0;i 0) { while (pennies[0][npennies-1] <= 0) // discard pennies that fall thru center { npennies--; accreta[naccreted] = myCurve(0.0); naccreted++; if (naccreted > maxacc) naccreted=100; //hard cap println("accreted! to "+ naccreted + " " + accreta[naccreted]); if (npennies <= 0) break; } } // track accreted objects if (naccreted > 0) { while (accreta[0] > 500 && naccreted > 0) //let some accreta fall off bottom of view { naccreted--; println("fell off bottom"); for (int i=0;i npennies-1) continue; if (abs(pennies[1][i] - pennies[1][j])*pennies[0][i] < 10) { if (abs(pennies[0][i] - pennies[0][j]) < 10) //close in radius { pushMatrix(); translate(pennies[0][i]*cos(pennies[1][i]), myCurve(pennies[0][i]), pennies[0][i]*sin(pennies[1][i])); fill(10,1,1); noStroke(); sphere(10); // "collision" flash popMatrix(); //move in consequence float kicksize = (random(5)+5)/sqrt(1+pow(5.0/(sqrt(pennies[0][i])),2)); // println(pennies[0][i] + " " + kicksize); pennies[0][i] += kicksize; pennies[0][j] -= kicksize; sortPennies(); } } } } }