FlowFieldRunner runner = new FlowFieldRunner(); void setup() { //size(1800, 1000); size(600, 600); sample00(); } void draw() { runner.update(); } void keyPressed() { println(" key " + key + " pressed"); if (key == 's') { String fn = "captures/" + runner.sampleName + ".png"; save(fn); } } void sample00() { background(color(219, 237, 243)); println("gen new noise"); NoiseGenerator ngen = new NoiseGenerator(0.01, 0.5); ngen.setNoiseOctaveParam(3, 0.3); // TODO: remove me sampleName runner.sampleName = "sample00"; runner.addLayer(new ParticlesLayer(10000,600, color(40, 49, 73), ngen) { public void draw(Particle p) { strokeWeight(1); stroke(p.c, 5); line(p.prev.x, p.prev.y, p.pos.x, p.pos.y); } }); } class FlowFieldRunner { ArrayList layers; ParticlesLayer currentLayer; int currentLayerIndex = -1; boolean start = true; String sampleName = ""; boolean draw_done = false; FlowFieldRunner() { layers = new ArrayList(); } void addLayer(ParticlesLayer pl) { if (currentLayerIndex == -1) { currentLayerIndex = 0; currentLayer = pl; } layers.add(pl); } boolean getDrawDone(){ return draw_done; } void resetDrawDone(){ draw_done = false; } void update() { if (start) { this.start = false; println("Layer " + (currentLayerIndex + 1) + " started"); currentLayer.init(); } if (currentLayer.dead) { if (currentLayerIndex < layers.size() - 1) { println("Layer " + (currentLayerIndex + 1) + " done"); currentLayerIndex++; println("Layer " + (currentLayerIndex + 1) + " started"); currentLayer = layers.get(currentLayerIndex); currentLayer.init(); } else { println("Layer " + (currentLayerIndex + 1) + " done"); println("All layers drawn :-)"); draw_done = true; } } else { // updatecurrent layer currentLayer.update(); } } } class ParticlesLayer { boolean dead = false; ArrayList particles; int deadCount; int aliveCount; int lifeTime; NoiseGenerator noiseGenerator; color c; ParticlesLayer(int count, int lifeTime, color c, NoiseGenerator noiseGenerator) { this.deadCount = 0; this.aliveCount = count; this.noiseGenerator = noiseGenerator; this.lifeTime = lifeTime; this.c = c; particles = new ArrayList(); for( int x = 0; x < count; x++) { particles.add( new Particle( new PVector(-100+random(width+200), -100+random(height+200)) , this.lifeTime, this.c, this.noiseGenerator)); } } void init() { this.noiseGenerator.init(); } void update() { if(dead) return; for( int x = 0; x < aliveCount; x++) { Particle p = particles.get(x); if( !p.dead) { p.update(); this.draw(p); if( p.dead) { deadCount++; } } } if( deadCount == aliveCount) { //println("All particles of this layer are dead"); dead = true; } noiseGenerator.update(); } void draw( Particle p) { // to be override to customize drawing } } class NoiseGenerator { float noiseScale; float forceScale; float noiseZInc; float noiseZ; int noiseOctave; float noiseFalloff; NoiseGenerator(float noiseScale, float forceScale) { this.noiseScale = noiseScale; this.forceScale = forceScale; this.noiseZInc = 0.0; this.noiseZ = 0.0; this.noiseOctave = 4; this.noiseFalloff = 0.5; } float getNoiseAt( float x, float y ) { return noise(x*noiseScale, y*noiseScale, noiseZ); } void setNoiseOctaveParam(int octaves, float fallOff) { this.noiseOctave = octaves; this.noiseFalloff = fallOff; } void setZNoise( float startZNoise, float zNoiseInc) { this.noiseZInc = zNoiseInc; this.noiseZ = startZNoise; } PVector getForceAt(float x, float y) { float n = noise(x * noiseScale, y * noiseScale, noiseZ )*TWO_PI; PVector force = PVector.fromAngle(n); force = force.mult(forceScale); return force; } void init() { //println("NoiseGenerator::init - octave "+this.noiseOctave+" falloff "+this.noiseFalloff+""); noiseDetail(this.noiseOctave, this.noiseFalloff); } void update() { noiseZ += noiseZInc; } } class Particle { PVector pos; PVector prev; color c; int lifeTime; int startLifeTime; boolean dead; NoiseGenerator noiseGenerator; Particle(PVector pos, int lifeTime, color c, NoiseGenerator noiseGenerator) { this.pos = pos; this.prev = pos; this.lifeTime = lifeTime; this.startLifeTime = lifeTime; this.c = c; this.dead = false; this.noiseGenerator = noiseGenerator; } void update() { this.lifeTime--; if( this.lifeTime <= 0) { this.dead = true; } else { this.prev = this.pos; this.pos.add(this.noiseGenerator.getForceAt(this.pos.x, this.pos.y)); } } }