// sandtoy // - a game engine experiment // // 2003 Scott "Jerry" Lawrence // http://www.cis.rit.edu/~jerry/Software/p5 // // based on concepts discussed with Rob Reay many years ago. int maxgrain = 2048; Granule sand[] = new Granule[maxgrain]; int granules = 0; boolean locked = true; int settle = 1; RectButton r1, r2, r3; void setup() { size( 200, 200 ); background( 0 ); r1 = new RectButton( 5, 5, 20, color(120, 75, 0), color(240, 150, 0) ); r2 = new RectButton( 30, 5, 20, color( 0, 0, 120), color( 0, 0, 240) ); r3 = new RectButton( 80, 5, 20, color( 150, 0, 0), color(255, 0, 0) ); } void loop() { r1.display(); r2.display(); r3.display(); r1.update(); r2.update(); r3.update(); // status slider bar frame, backing stroke( 255 ); fill( 0, 60, 0 ); rect( 100, 5, 90, 20 ); // status slider bar indicator noStroke(); if( settle == 1 ) fill( 240, 150, 0 ); else fill( 0, 0, 240 ); float p = ( (float) granules / (float) maxgrain ) * 90.0; rect( 101, 6, (int)p , 19 ); // draw something interesting at the bottom stroke( 60 ); line( 100, 175, 100, height ); line( 99, 175, 99, height ); line( 100, 190, 130, 190 ); if( mousePressed ) //&& mouseX > 80 && mouseX < 120 ) { if( r1.pressed() ) { settle = 1; } else if( r2.pressed() ) { settle = 2; } else if( r3.pressed() ) { granules = constrain( granules-10, 0, granules ); } else if( mouseX >100 && mouseX < 190 && mouseY>5 && mouseY<25 ) { // in the sliderwidget granules = constrain( (int)((float)(mouseX-100) * (float)maxgrain / 90), 0, granules ); } else if( (granules+10) < maxgrain ) { for( int j = 0 ; j < 10 ; j++ ) { int xx = mouseX + (int) random(5); int yy = mouseY + (int) random(5); if( !collide( xx, yy )) { sand[ granules ] = new Granule( xx, yy ); granules++; } } } } if( keyPressed ) { if( key == 'r' ) { granules = 0; } } // update and draw for( int i = 0 ; i < granules ; i++ ) { sand[i].update(); sand[i].draw(); } /* if( keyPressed ) { if( key == 'G' ) { screenGrab(); } } */ } class Granule { int x; int y; int speed = 1; color c; boolean moving = false; Granule( int xx, int yy ) { x = xx; // float( xx ); y = yy; //float( yy ); if( (second() & 1) == 1 ) { c = color( 255-yy, 55+yy, 255 ); } else { c = color( 55+yy, 255, 0 ); } moving = true; } boolean iAmAt( int xx, int yy ) { if(( xx == (int)x ) && ( yy == (int) y )) return( true ); else return( false ); } void update() { // attempt to drop if( !collide( (int)x, (int)(y+speed)) ) { y+= speed; } else { // otherwise, attempt to settle // this is super slow if( random(100) < 5 ) { if( settle == 1 ) { if( (x-1>=0) && (y 5)) { x--; y++; } else if( (x+1 5)) { x++; y++; } } else { if( !collide( (int)x-1, (int)y ) ) x--; else if( !collide( (int)x+1, (int)y ) ) x++; } } } } void draw() { setPixel( (int)x, (int)y, c ); // fill( c ); // rect( x, y, 2, 2 ); } } // grainAt -- returns true if there is a grain at (xx,yy) boolean grainAt( int xx, int yy ) { for( int k = 0 ; k < granules ; k++ ) { if( sand[ k ].iAmAt( xx, yy ) ) return( true ); } return( false ); } // collide -- returns true if there is something blocking us boolean collide( int x, int y ) { if( x < 0 || x >= width || y < 0 || y >= height ) return( true ); if( getPixel( x, y ) != color( 0, 0, 0 ) ) return( true ); return( false ); } class Button { int x, y; int size; color basecolor, highlightcolor; color currentcolor; boolean over = false; boolean pressed = false; void update() { if(over()) { currentcolor = highlightcolor; } else { currentcolor = basecolor; } } boolean pressed() { if(over) { locked = true; return true; } else { locked = false; return false; } } boolean over() { return true; } void display() { } } class CircleButton extends Button { CircleButton(int _x, int _y, int _size, color _color, color _highlight) { x = _x; y = _y; size = _size; basecolor = _color; highlightcolor = _highlight; currentcolor = basecolor; } boolean over() { if( overCircle(x, y, size) ) { over = true; return true; } else { over = false; return false; } } void display() { stroke(255); fill(currentcolor); ellipse(x, y, size, size); } } class RectButton extends Button { RectButton(int _x, int _y, int _size, color _color, color _highlight) { x = _x; y = _y; size = _size; basecolor = _color; highlightcolor = _highlight; currentcolor = basecolor; } boolean over() { if( overRect(x, y, size, size) ) { over = true; return true; } else { over = false; return false; } } void display() { stroke(255); fill(currentcolor); rect(x, y, size, size); } } boolean overRect(int x, int y, int width, int height) { if (mouseX >= x && mouseX <= x+width && mouseY >= y && mouseY <= y+height) { return true; } else { return false; } } boolean overCircle(int x, int y, int diameter) { float disX = x - mouseX; float disY = y - mouseY; if(sqrt(sq(disX) + sq(disY)) < diameter/2 ) { return true; } else { return false; } }