// dynamics.pde // // 8 Dec 2010: Sample copied from // http://processing.org/discourse/yabb2/YaBB.pl?num=1267698314 // and ported to the Traer Processingjs library -mrn // 10 Dec 2010: Added a run state indicator -mrn // 12 Dec 2010: Moved Buttons and Traer physics into separate pde files, // added repulsion slider -mrn // 17 Dec 2010: Added fps reading and a button to set frameRate(60) or frameRate(9999) -mrn // Last updated: 17 Dec 2010 10:01, Mike Niemi // NOTE: To run this in the Processing IDE, uncomment the first line of code in gimeMillis() and comment out the next. // To run this in Processing.js, comment out the first line of code in gimeMillis() and uncomment the 2nd. int n = 10, kVal = -5; ParticleSystem physics; int SOMEdelay = 300, i0 = 0, pi = -1; boolean justStarting = true, IDE = false; StateButton runStateButton; boolean running = true; HScrollbar hs1; long startMillis = 0, totalCycles = 0, totalMillis = 0; PushButton limitFrameRateButton; int limitingFrameRateState = 0; UniversalAttraction uniAtt; long gimeMillis() { //IDE=true; return System.currentTimeMillis(); // <-- Uncomment this line when running in the Processing IDE (Java) // AND comment out the next line of code. IDE = false; return gimeMillis2(); // <-- Uncomment this line when running in Processing.js // AND comment out the previous line of code. // The supporting code in the HTML looks like this: // } void setup() { size(200,200); smooth(); ellipseMode( CENTER ); physics = new ParticleSystem( 1, 0.05 ); resetModel(); gimeMillis(); runStateButton = new StateButton(-5, -5, 20, 255, 153, 0); hs1 = new HScrollbar(1, 194, 50, 10, 1); limitFrameRateButton = new PushButton(IDE?105:87, IDE?1:3, IDE?92:70, IDE?13:9, "F.R. Undefined", "F.R. Limited", "F.R. Unlimited"); } void resetModel() { physics.clear(); ArrayList unfixed = new ArrayList(); for (int i=0; i SOMEdelay) { // After a while, put our view to sleep to avoid consuming CPU cycles. //println("draw(): going to sleep now"); running = false; noLoop(); } background(0); runStateButton.display( running?runStateButton.STATEon:runStateButton.STATEoff, // Sets the red indicator SOMEdelay-i0 ); // Tempered by how many cycles until we go to sleep limitFrameRateButton.display(limitingFrameRateState); if (hs1.update(SOMEdelay-i0)) // Sometimes the slider does not quiesce automatically when the mouse leaves it. { // The arg causes the slider to turn off its color in sync with the runStateButton. calcAttractions(hs1.getValue()); i0 = 0; } physics.tick(); hs1.display(); fill(128,0,0); text("Repulsion", 4, 198); if ( justStarting && i0>50 ) // Display this text after the 50th cycle when justStarting { float f = 255; if (i0 < 100) f = ((float)i0-50.0)/50.0*255; // 0.0-255.0 .. fade-in the text over 50 cycles fill(f); text("Click on upper half to restart", 25, 40); text("Click on lower half to perturb", 25, 55); text("Move slider to change repulsion", 25, 70); } fill(255); long currMillis = gimeMillis(); float f = ((float)totalCycles) *1000.0 / (float)(currMillis - startMillis); f = ((float)((int)(f*1000.0)))/1000.0; // Limit to 3 decimal places text(f, 25, 12); text("fps", IDE?77:67, 12); stroke(255, 200); for (Iterator i = physics.springs.iterator(); i.hasNext(); ) { Spring s = (Spring)i.next(); Particle pend = s.getOneEnd(); Particle anchor = s.getTheOtherEnd(); line( pend.position.x, pend.position.y, anchor.position.x, anchor.position.y ); ellipse( anchor.position.x, anchor.position.y, 5, 5 ); ellipse( pend.position.x, pend.position.y, 20, 20 ); } } void mousePressed() { i0 = 0; justStarting = false; if (!running) // We have just been reawakened startMillis = totalCycles = 0; if (hs1.over()) { running = true; loop(); return; } if (runStateButton.over()) { running = !running; if (running) loop(); // Wake up the view else i0 = SOMEdelay; // let draw() put us to sleep return; } if (limitFrameRateButton.over()) // Undefined > Limited > Unlimited > Limited > ... { switch(limitingFrameRateState) { case 0: limitingFrameRateState=1; frameRate(60); break; case 1: limitingFrameRateState=2; frameRate(9999); break; case 2: limitingFrameRateState=1; frameRate(60); break; default: limitingFrameRateState=2; frameRate(9999); } running = true; loop(); return; } if (mouseY < height/2) { // The mouse is in the upper half - do a reset physics.clear(); if (perturbation != null) perturbation = null; resetModel(); } else { // Otherwise, the mouse is in the lower half - create a new perturbation PVector perturbation = new PVector( mouseX, mouseY, 0f ); calcPerturbation(perturbation); } running = true; loop(); // Wake up the view (if not already awake) }