Particles
Class Particle
Code below modified from Shiffman's Nature of Code
//From Shiffman, Nature of Code, Chapter 4
//Modified to use PShape and to modify color: HSB with particle age
class Particle {
//Particle has location, velocity, and acceleration, PShape, color, lifespan
PVector location;
PVector velocity;
PVector acceleration;
float lifetime, lifespanMax;
PShape s;
color c;
//CONSTRUCTOR
Particle(PVector l, PShape s, color c) { //create particle at location: l
location = new PVector(); //initailize PVector
location.set(l); //set location with parameter l
this.s=s ;
this.c = c;
//For demonstration purposes we assign the Particle an initial velocity and constant acceleration.
acceleration = new PVector(0,random(0.1, .05));
velocity = new PVector(random(-.5,1),random(-2.5,0));
lifespanMax = random( 50, 100);
lifetime = lifespanMax;
}
void update() {
velocity.add(acceleration);
location.add(velocity);
lifetime -=1;
}
void display() {
//Use changing lifetime compared to lifespanMax - to change brightness and hue
if( s.getChildCount()==0){ //change fill if PShape does not have children
float fractionDecr = map( lifetime, lifespanMax/2, 0, 1.0 ,random( 0.6, .2));
float fractionIncr = map( lifetime, lifespanMax, 0, 0.8 ,1.0);
s.setFill( color(hue(c)*fractionIncr, saturation(c)*fractionIncr, brightness( c) * fractionDecr));
}
shape(s, location.x, location.y);
}
void run() {
update();
if( frameCount %2 == 0){ //don't display every frame, use modulus to give pause
display();
}
}
boolean isDead() {
//Is the particle still alive?
if (lifetime < 0.0) {
return true;
} else {
return false;
}
}
}
Class Particle System
import java.util.Iterator;
class ParticleSystem {
//One list, for anything that is a Particle or extends Particle
ArrayList<Particle> particles;
PVector origin;
ParticleSystem(PVector location) {
origin = new PVector();
origin.set(location);
particles = new ArrayList<Particle>();
}
void addParticle(PVector location, PShape s, color c) {
Particle particle = new Particle( location, s, c);
particles.add(particle);
}
void run() {
Iterator<Particle> it = particles.iterator();
while (it.hasNext()) {
//Polymorphism allows us to treat everything as a Particle, whether it is a Particle or a Confetti.
Particle p = it.next();
p.run();
if (p.isDead()) {
it.remove();
}
}
}
}
Example Main-Tab Code:
Requires use of All Project 3 Classes. The main-tab code has been refactored in several ways to
Button clearButton, particleButton; //data-type, variable-name //null
color bkgColor, globalColor; //global since used in several different functions
ParticleSystem ps;
ButtonGroup btnGroup; //will refer to a ButtonGroup object instance
Pattern curPattern;
Pattern pattern1, pattern2, pattern3, eraserPattern; ///4 patterns to match 4 buttons
Slider hueSlider, satSlider, brightSlider, scaleSlider; //base-class variable type
///Initialize things - variables
void setup(){
size( 1000, 800);
colorMode(HSB, 360, 100, 100);
bkgColor = color(50);//dark gray
background( bkgColor);///sets the background once with bkgCOlor
//Initialize Pattern Objects
//Place-holder PShapes
ps = new ParticleSystem(new PVector(width/2,50)); //starting position
PShape s0 = createShape( ELLIPSE, 0,0,10, 10); //this is fine
//Call constructors to create the objects
eraserPattern = new Pattern( s0, bkgColor); //pattern0
eraserPattern.strokeColor = bkgColor;
curPattern = eraserPattern;
//the image named below must be in a folder named 'data'
//that you will create inside your sketch folder
PImage img1 = loadImage("pattern1Btn.png" );
PImage img3 = loadImage("btn3Img.png" );
///image( img1, 200,200); //test the image
clearButton = new Button( 10, 10, 100, 100, "Clear" ); //initialize by calling a Button constructor
particleButton = new Button( 10, 600, 100, 100, "Particles");
//local variable - we use the ButtonGroup instead of the btnArray in program
Button[] btnArray; //declare the variable - of the Base-class type: Button //null
btnArray = new Button[4]; //initialize the array so it has 3 button elements
// PImageButton(float x, float y, float w, float h, PImage img)
btnArray[0] = new Button( 10, 120, 100, 100, "Eraser" );
btnArray[1] = new Button( 10, 230, 100, 100, "Btn1" );
btnArray[2] = new Button( 10, 340, 100, 100, "Btn2" );
btnArray[3] = new Button( 10, 450, 100, 100, "Btn3");
btnGroup = new ButtonGroup(btnArray); //Call constructor for ButtonGroup, pass in array
//initialize sliders
hueSlider = new HueSlider( 140, 700, 150, 40, 100, 260);
satSlider = new SatSlider( 380, 700, 150, 40, 0, 100);
satSlider.hue = hueSlider.sliderVal;
brightSlider = new Slider( 620, 700, 150, 40, 0, 100, "Bright");
scaleSlider = new Slider( 850, 700, 130, 40, 0.0, 2.0, "Scale");
}//in setup
//makes it a frame-based application
void draw( ){
if(mousePressed){
if( particleButton.selected){ //when particleButton is active
ps.addParticle(new PVector( mouseX,mouseY), curPattern.s, globalColor);
}
if(checkSliders()){ //check if sliders have been changed
changePattern();
}
pushMatrix();
translate( mouseX, mouseY);
displayPattern();
popMatrix();
}
ps.run(); //particle display - animation happens here
displayButtons();
displaySliders();
}
void mouseClicked( ){
clearButton.clicked( mouseX, mouseY);
particleButton.clicked( mouseX, mouseY);
if( clearButton.selected){
clearCanvas();
clearButton.reset(); //turn off like a doorbell
}
if(btnGroup.clicked( mouseX, mouseY)){
changePattern();
}
}
void displaySliders(){
fill( 0); //draw black background rectangle
rect( 120, 650, width, height - 650);
hueSlider.display();
satSlider.display();
brightSlider.display();
scaleSlider.display();
}
boolean checkSliders(){
boolean changed = false;
if(hueSlider.checkPressed( mouseX, mouseY)){
changed = true;
satSlider.hue = hueSlider.sliderVal;
brightSlider.hue = hueSlider.sliderVal;
}
if(satSlider.checkPressed( mouseX, mouseY)){
changed = true;
brightSlider.sat = satSlider.sliderVal;
}
if(brightSlider.checkPressed( mouseX, mouseY)){
changed=true;
}
globalColor = color( hueSlider.sliderVal, satSlider.sliderVal, brightSlider.sliderVal);
if( scaleSlider.checkPressed(mouseX, mouseY)){
changed = true;
}
return changed;
}
//Contains logic to connect ButtonGroup buttons to control which patterns is drawn
void changePattern(){
int activeButton = btnGroup.activeBtnIndex;
float len = 100;
len *= scaleSlider.sliderVal;
//use global curPattern
switch( activeButton ){ ///connects the buttons to the patterns
//active button sets curPattern
case 0: ///eraser button is ButtonArray[0]
PShape s0 = createShape( ELLIPSE, 0,0,len, len); //this is fine
//Call constructors to create the objects
eraserPattern = new Pattern( s0); //pattern0
eraserPattern.fillColor = bkgColor;
eraserPattern.strokeColor = bkgColor;
curPattern = eraserPattern;
break;
case 1:
PShape s1 = createShape( ELLIPSE, 0,0,len , len/2 );
pattern1 = new Pattern( s1);
curPattern = pattern1;
break;
case 2:
PShape s2 = createShape( RECT, 0,0,len , len ); //call vertexShape function
pattern2 = new Pattern( s2);
curPattern = pattern2;
break;
case 3:
PShape g = createShape(GROUP);
recursiveShapes(g,len,5, globalColor); //call vertexShape function
pattern3 = new Pattern( g);
curPattern = pattern3;
break;
default:
//none of the cases were a match
println("no match on switch-case");
break;
} //end of switch
////once we know the current pattern, then we are setting the fill and stroke
} //end drawPattern
void displayPattern(){
if( curPattern != eraserPattern){ //for all other patterns set the stroke and fill
curPattern.fillColor = color( globalColor);
curPattern.strokeColor = color(0); //black
}
curPattern.display(); //display for every pattern
}
void displayButtons( ){
fill( 0);
rect( 0,0,120, height);
clearButton.display(); //have the button instance call it's display( ) method
btnGroup.display(); //ButtonGroup has each button display itself
particleButton.display();
}
void clearCanvas(){
///do something to 'clear the canvas'
}
PShape vertexShape1( float len, color curColor ) {
PShape s = createShape( );
s.setFill(curColor);
s.beginShape();
s.vertex(len * .5, len * .5);
s.vertex( 0, 0);
s.vertex(len, 0);
s.vertex( len * .5, len * .5);
s.vertex( len, len);
s.vertex(0, len);
s.vertex( len * .5, len * .5);
s.endShape(CLOSE);
return s;
} //end createOneShape
void recursiveShapes(PShape group, float len, int level, color c1 ){
if( level < 1){
return;
}
color curColor = color( hue( c1), saturation(c1), brightness(c1) *.8);
PShape s = vertexShape1( len, curColor);
group.addChild(s);
recursiveShapes( group, len *.8, level-1, curColor);
}
Last updated