int NUMBRANCHES = 6; int NUMLEAVES = 30; void keyPressed() { if(key == ' '){ reset();} } void reset(){ tree.calcBranches(); winds = new ArrayList(); freeLeaves = new ArrayList(); } ArrayList winds;// = new ArrayList(); ArrayList freeLeaves;// = new ArrayList(); Tree tree = new Tree(); void setup() { size(500, 500); reset(); } void draw() { background(100, 200, 100); //if(isDrawing) line(sx,sy,ex,ey); for(Leaf v : freeLeaves){ if( (! v.isFalling()) && v.y < 250) v.draw(); } tree.draw(); for(Leaf v : freeLeaves){ if(v.isFalling() || v.y >= 250) v.draw(); v.move(); } ArrayList windsToKill = new ArrayList(); for (Wind w : winds) { if (!w.draw()) { windsToKill.add(w); }; } winds.removeAll(windsToKill); //frameRate(5); } float sx, sy, ex, ey; boolean isDrawing = false; void mousePressed() { sx = mouseX; sy = mouseY; ex = mouseX; ey = mouseY; isDrawing = true; } void mouseDragged() { ex = mouseX; ey = mouseY; } void mouseReleased() { isDrawing = false; winds.add(new Wind(sx, sy, ex, ey)); } class Wind { ArrayList breezes = new ArrayList(); Wind(float sx, float sy, float ex, float ey) { for (int i = 0; i < 5; i++) { float offx = random(-30, 30); float offy = random(-30, 30); breezes.add(new Breeze(sx+offx, sy+offy, ex+offx, ey+offy)); } } boolean draw() { strokeWeight(1); boolean stop = false; ; stroke(200); for (Breeze b : breezes) { if (! b.move()) stop = true; b.draw(); } return !stop; } } class Breeze { final int NUMPARTS = 40; ArrayList points = new ArrayList(); int curlToDraw = 25; float a;float origa; float hx, hy; float turn = .3 + random(-.1, .1); Breeze(float sx, float sy, float ex, float ey) { for (int i = 0; i <= NUMPARTS; i++) { points.add(new Point(lerp(sx, ex, (float)i/(float)NUMPARTS), lerp(sy, ey, (float)i/(float)NUMPARTS))); } hx = ex; hy = ey; if (random(1) < .5) turn *= -1; a = atan2(ey-sy, ex-sx); origa = a; } boolean move() { if (curlToDraw >= 0) { curlToDraw--; hx += cos(a ) * 8; hy += sin(a ) * 8; a += turn; points.add(new Point(hx, hy)); } for (Branch b : tree.branches) { b.rustle(this); } for(Leaf v : freeLeaves){ v.rustle(this) ; } if (points.size() > 0) { points.remove(0); } return points.size() > 0; } void draw() { if (points.size() <= 0) return; Point lastPoint = points.get(0); for (int i = 1; i < points.size(); i++) { Point point = points.get(i); pointline(i, lastPoint, point); lastPoint = point; } } } void pointline(int i, Point p1, Point p2) { // println(i+" "+p1.x+" "+p1.y+" "+p2.x+" "+p2.y); line(p1.x, p1.y, p2.x, p2.y); } class Point { float x, y; Point(float px, float py) { x = px; y = py; } } class Tree { ArrayList branches; void draw() { for (Branch b : branches) { b.move(); b.draw(); b.drawLeaves(); } for (Branch b : branches) { //draw leaves after so in front of tree b.drawLeaves(); } } void calcBranches() { branches = new ArrayList(); for (int i = 0; i < NUMBRANCHES; i++) branches.add(new Branch()); } } class Branch { float sx, sy, ex, ey, sgx, sgy, egx, egy; float pushx = 0, pushy = 0; ArrayList leaves = new ArrayList(); Branch() { float xoff = random(-3, 3); sx = 250+xoff; sy = 250; sgx = 250+xoff; sgy = 150; ex = sx + random(-50, 50); ey = 150 - random(0, 50); egx = random(240, 260); egy = random(190, 210); for (int i = 0; i < NUMLEAVES; i++) { leaves.add(new Leaf(this)); } } void move() { pushx *= .8; pushy *= .8; } void draw() { strokeWeight(8); stroke(128, 64, 0); noFill(); bezier(sx, sy, sgx, sgy, egx, egy, ex+pushx, ey+pushy); } void drawLeaves() { ArrayList leavesBlown = new ArrayList(); for (Leaf v : leaves) { v.draw(); if(v.blownOff()){ leavesBlown.add(v); } } leaves.removeAll(leavesBlown); freeLeaves.addAll(leavesBlown); } void rustle(Breeze b) { if (dist(b.hx, b.hy, ex, ey) < 200) { pushx += cos(b.a) ; pushy += sin(b.a); } } } class Leaf { Branch b; boolean attached = true; int fallTime; float x, y ; color c; float SPREAD = 20; Leaf(Branch parent) { b = parent; x = random(-SPREAD, SPREAD); y = random(-SPREAD, SPREAD); c = color(250,random(128,255),0); } void draw() { /*if(! attached){ stroke(0);strokeWeight(1);line(250,250,x,y); }*/ noStroke(); fill(c); if(attached){ ellipse(x + b.ex + b.pushx, y + b.ey + b.pushy, 5, 5); } else { ellipse(x ,y, 5, 5); } } void move(){ if(fallTime > 0){ fallTime--; y++; x += random(-1,1); } } boolean blownOff(){ float f = dist(0,0,b.pushx,b.pushy); // how strong pushed? might break off if(f > 5 && random(1)< .01){ attached = false; fallTime = round(250 - ey); x += ex; y += ey; return true; } return false; } boolean isFalling(){ return fallTime > 0; } void rustle(Breeze b) { if (dist(b.hx, b.hy, x, y) < 200) { if(random(1)<.3){ float xoff = cos(b.origa) + random(-1,1) ; if(isFalling()) xoff *= .2; x += xoff; y += sin(b.origa) + random(-1,1) ; } } } }