Art›Pi Firework
Cluster.pde
class Cluster {
Dot[] dots;
ArrayList<FloatList> explosions;
float explosion_radius_min = 400;
float explosion_radius_max = 450;
float explosion_frames = 60;
Cluster() {
// arraylist to record explosion points/states
explosions = new ArrayList<FloatList>();
// load image
PImage pimg = loadImage("pi.jpg");
// create dots array, pull random black pixel for each dot
dots = new Dot[1700];
for(int i = 0; i < dots.length; i++) {
// pick random black pixel
int px = 0;
int py = 0;
int attempts = 0;
int max_attempts = 500;
while((attempts < max_attempts) && (px == 0) && (py == 0)) {
attempts++;
px = floor(random(pimg.width));
py = floor(random(pimg.height));
color pcol = pimg.get(px, py);
if(red(pcol) > 100) {
px = 0;
py = 0;
} else {
// check other dots
if(i > 0) {
for(int k = 0; k < i; k++) {
float distance = dist(px, py, dots[ k ].x, dots[ k ].y);
if(distance <= 9.8) {
px = 0;
py = 0;
}
}
}
}
}
int dotpx = floor(px);//int dotpx = floor(map(px, 0, pimg.width, 0, width));
int dotpy = floor(py);//int dotpy = floor(map(py, 0, pimg.height, 0, height));
dots[ i ] = new Dot(dotpx, dotpy);
}
}
void explodeAt(float x, float y) {
//println("explodeAt("+ x +","+ y +")");
FloatList explosion = new FloatList();
explosion.append((float)x);
explosion.append((float)y);
explosion.append(0.0);
explosion.append(random(explosion_radius_min, explosion_radius_max));
explosions.add(explosion);
}
void update() {
// clear out finished explosions
for(int i = explosions.size() - 1; i >= 0; i--) {
FloatList exp = explosions.get(i);
if(exp.get(2) >= 1) {
explosions.remove(i);
}
}
// increase explosion radius
for(int i = 0; i < explosions.size(); i++) {
FloatList exp = explosions.get(i);
exp.set(2, (exp.get(2) + (1 / explosion_frames) ));
}
}
void draw() {
for(int j = 0; j < dots.length; j++) {
Dot dot = dots[j];
for(int i = 0; i < explosions.size(); i++) {
FloatList exp = explosions.get(i);
dot.processExplosion(exp.get(0), exp.get(1), (exp.get(3) * exp.get(2)));
}
dot.draw();
}
}
}
Dot.pde
class Dot {
float x;
float y;
color col;
float opacity = 0; // 0-100
float opacity_decrease_rate_per_frame = 2;
Dot(int x_, int y_) {
x = ((float)x_ + random(-1, 1));
y = ((float)y_ + random(-1, 1));
color col_blue = color(21, 107, 193);
color col_green = color(6, 229, 78);
//col = lerpColor(col_blue, col_green, norm((((float)x / (float)width) + ((float)y / (float)height)), 0, 2));
col = lerpColor(col_blue, col_green, norm((((float)x / (float)width) + ((float)y / (float)height)), 0, 2));
}
void processExplosion(float ex, float ey, float eradius) {
// ex,ey = explosion epicenter
// estate = 0-1 range of explosion state
// eradius = max radius of explosion
float raw_distance = dist(x, y, ex, ey);
//if(raw_distance <= eradius) {
// opacity = 100;
//}
// shouldn't always be on if in radius of explosion, so set range
if(abs((raw_distance - eradius)) <= 5) {
opacity = 100;
}
}
void draw() {
if(opacity > 0) {
push();
int this_opacity = 100;
if(opacity < 75) {
this_opacity = floor((100 * norm(opacity, 0, 75)));
}
color coll = color(red(col), green(col), blue(col), (2.5 * this_opacity));
//stroke(coll);
//strokeWeight(4);
//point(x, y);
translate(x, y);
fill(coll);
noStroke();
rect(-4, -4, 8, 8);
//ellipseMode(CENTER);
//ellipse(0, 0, 4, 4);
pop();
opacity = max(0, (opacity - opacity_decrease_rate_per_frame));
}
}
}
Firework.pde
class Firework {
//PVector vel_default;
PVector pos;
PVector vel;
PVector acc;
PVector grav;
PVector exploded_at;
boolean exploded = false;
ArrayList<PVector> particles;
float particle_dist = 0;
float particle_speed = 5;
int explosion_frames = 0;
int explosion_frame_limit = 30;
boolean is_exploded_done;
Firework(float x, float y) {
//vel_default = new PVector(0, random(-12, -25));
grav = new PVector(random(-0.03, 0.03), random(0.1, 0.3));
particles = new ArrayList<PVector>();
pos = new PVector(x, y);
//vel = vel_default.copy();
vel = new PVector(0, random(-12.5, -20));
acc = new PVector(0, 0);
}
//void setPos(float x, float y) {
// //println("setPos.old="+ pos.x +","+ pos.y +" :: new="+ x +","+ y);
// pos = new PVector(x, y);
// vel = vel_default.copy();
// acc.mult(0);
//
// exploded = false;
//}
void applyForce(PVector force) {
acc.add(force);
}
void update() {
applyForce(grav);
vel.add(acc);
pos.add(vel);
acc.mult(0);
//println(vel.y);
}
void show(Cluster obj) {
if(vel.y < 6) {
push();
stroke(255);
strokeWeight(4);
point(pos.x, pos.y);
pop();
} else {
if(!exploded) {
// explode here
exploded_at = new PVector(pos.x, pos.y);
obj.explodeAt(pos.x, pos.y);
int num_particles = floor(random(10, 25));
for(int i = 0; i < num_particles; i++) {
particles.add(PVector.random3D());
}
exploded = true;
}
if(explosion_frames < explosion_frame_limit) {
push();
translate(exploded_at.x, exploded_at.y);
stroke(color(255, 255, 255, map(explosion_frames, 0, explosion_frame_limit, 255, 30)));
strokeWeight(2);
for(PVector particle : particles) {
point((particle_dist * particle.x * (0.75 + particle.z)), (particle_dist * particle.y * (0.75 + particle.z)));
}
pop();
particle_dist += particle_speed;
explosion_frames++;
} else {
is_exploded_done = true;
}
}
}
boolean outOfBounds() {
return ((this.pos.x < -15) || (this.pos.x > (width + 15)) || (this.pos.y > (height + 15)));
}
boolean isDone() {
//return (exploded || outOfBounds());
return is_exploded_done;
}
}
pi_firework.pde
ArrayList<Firework> fireworks;
//PVector gravity;
Cluster cluster;
int fireworkEveryNumFrames = 60;
void setup() {
size(640, 640, P2D);
//smooth(8);
noSmooth();
//firework = new Firework((float)random(30, (width - 30)), (float)height);
fireworks = new ArrayList<Firework>();
//gravity = new PVector(random(-0.03, 0.03), 0.2);
cluster = new Cluster();
}
void draw() {
background(30);
if((frameCount % fireworkEveryNumFrames) == 0) {
fireworks.add(new Firework((float)random(30, (width - 30)), (float)height));
}
for(int i = (fireworks.size() - 1); i >= 0; i--) {
Firework firework = fireworks.get(i);
//firework.applyForce(gravity);
firework.update();
firework.show(cluster);
//if(firework.outOfBounds()) {
// println("outOfBounds");
// firework.setPos((float)random(30, (width - 30)), (float)height);
//
// gravity.x = random(-0.03, 0.03);
//}
if(firework.isDone()) {
fireworks.remove(i);
}
}
cluster.update();
cluster.draw();
// save frames
//if(frameCount <= 1800) {
// saveFrame("shots/preview-####.png");
//}
//
//if(frameCount == 1800) {
// println("done");
//}
//if(frameCount == 350) {
// save("preview.png");
//}
}
void push() { pushMatrix(); pushStyle(); }
void pop() { popStyle(); popMatrix(); }