float SNOW_FALL_INTERVAL = 2; Snow snow; SnowStack stack; void setup() { size(400,400); frameRate(20); background(0); snow = new Snow(); stack = new SnowStack(); } void draw() { fadeToBlack(); snow.draw(); stack.draw(); snow.newFlake(SNOW_FALL_INTERVAL); snow.checkFallen(stack); } void fadeToBlack() { fill(0,95); rectMode(CORNER); rect(0,0,width,height); } class Snow { ArrayList snow; Snow() { snow = new ArrayList(); } void checkFallen(SnowStack stack) { for( int i = 0 ; i < snow.size() ; i++ ) { SnowFlake s = (SnowFlake)snow.get(i); if( stack.checkFallen(s) ) { snow.remove(s); stack.add(s); } } } void newFlake(float interval) { if( random(interval) < 1.0 ) { snow.add(new SnowFlake()); } } void draw() { for( int i = 0 ; i < snow.size() ; i++ ) { SnowFlake s = (SnowFlake)snow.get(i); s.move(); s.draw(); } } } class SnowFlake { int MIN_RADIUS = 2; int MAX_RADIUS = 5; float MAX_HORIZONTAL_SPEED = 0.5; float MIN_FALL_SPEED = 1; float MAX_FALL_SPEED = 2; int MIN_INTERVAL = 50; int MAX_INTERVAL = 200; PVector p; PVector v; float r; int timeStep; int interval; SnowFlake() { timeStep = 0; p = new PVector(random(width), 0); v = new PVector(random(-MAX_HORIZONTAL_SPEED, MAX_HORIZONTAL_SPEED), random(MIN_FALL_SPEED, MAX_FALL_SPEED)); r = random(MIN_RADIUS, MAX_RADIUS); interval = (int)(random(MIN_INTERVAL, MAX_INTERVAL)); } void move() { timeStep++; p.add(v); while( p.x < 0 ) { p.x += width; } while( width < p.x ) { p.x -= width; } if( timeStep % interval == 0 ) { v.x = random(-MAX_HORIZONTAL_SPEED, MAX_HORIZONTAL_SPEED); } } void draw() { noStroke(); fill(255); // stroke(255); // fill(0); ellipse(p.x, p.y, r * 2, r * 2); } } class SnowStack { ArrayList stack; SnowStack() { stack = new ArrayList(); for( int i = 0 ; i < width / 5 ; i++ ) { stack.add(new PVector(i * 5, height)); } stack.add(new PVector(width, height)); } boolean checkFallen(SnowFlake s) { boolean yn = false; for(int i = 0 ; i < stack.size() - 1 ; i++ ) { PVector p1 = (PVector)stack.get(i ); PVector p2 = (PVector)stack.get(i + 1); float d = p1.dist(p2); if( p1.dist(s.p) < d && p2.dist(s.p) < d ) { float S = triangleArea(p1, p2, s.p); float h = 2 * S / p1.dist(p2); if( h < s.r ) { yn = true; } } } return yn; } float triangleArea(PVector p1, PVector p2, PVector p3) { float a = p1.dist(p2); float b = p2.dist(p3); float c = p3.dist(p1); float s = (a + b + c) / 2.0; return sqrt(s * (s - a) * (s - b) * (s - c)); } void add(SnowFlake s) { for(int i = 0 ; i < stack.size() - 1 ; i++ ) { PVector p1 = (PVector)stack.get(i ); PVector p2 = (PVector)stack.get(i + 1); float d = p1.dist(p2); if( p1.dist(s.p) < d && p2.dist(s.p) < d ) { float r = p1.dist(s.p) / (p1.dist(s.p) + p2.dist(s.p)); p1.y -= s.r * (1 - r); p2.y -= s.r * r; } } for(int i = 0 ; i < stack.size() - 1 ; i++ ) { PVector p1 = (PVector)stack.get(i ); PVector p2 = (PVector)stack.get(i + 1); float h = abs(p1.y - p2.y); float w = abs(p1.x - p2.x); if( w * 1.3 < h ) { p1.y = (p1.y + p2.y) / 2.0; p2.y = p1.y; } } } void draw() { noStroke(); fill(255); for( int i = 0 ; i < stack.size() - 1 ; i++ ) { PVector p1 = (PVector)stack.get(i ); PVector p2 = (PVector)stack.get(i + 1); quad(p1.x, p1.y, p1.x, height, p2.x + 1, height, p2.x + 1, p2.y); } } }