Creative code daily

day074

Please wait while the video is loading

Code

View on github

/**
 * Name: Day 74 -- 9950235
 */

import com.hamoid.*;

boolean isReadyForExport = true;

VideoExport export;

float maxFrameNumber = 1000; // The number of frame to record

int framesPerStep = 100;
int size = 20;
int[][] directions;
int[][] nextDirections;

int[][] getDirections(int step) {
  noiseSeed(1000 * step);
  int[][] res = new int[size][size];
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
      int v = round(noise(i * 0.2, j * 0.2) * 4);
      res[i][j] = v;
    }
  }
  return res;
}

int counter = 0;
int maxLife = 200;
class Particle {
  PVector position;
  PVector direction;
  float lifetime;
  color c;
  int id;

  Particle() {
    position = new PVector(0, 0);
    float angle = random(TWO_PI);
    direction = new PVector(3 * cos(angle), 3 * sin(angle));
    lifetime = frameCount + maxLife;
    c = #000000;
    id = counter++;
  }

  void update(PVector v) {
    direction.add(v);
    PVector newPos = PVector.add(position, direction);
    if (newPos.x > (width * 0.5) || newPos.x < -(width * 0.5) ) direction.set(-0.8 * direction.x, direction.y);
    else if (newPos.y > height * 0.5 || newPos.y < -(height * 0.5)) direction.set(direction.x, -0.8 * direction.y);
    else position = newPos;
  }

  boolean isDead() {
    return frameCount >= this.lifetime;
  }

  float remainingLife() {
    return (lifetime - frameCount) / maxLife;
  }
}

int radius = 350;
class PSystem {
  ArrayList<Particle> particles = new ArrayList<Particle>();

  PSystem(int nb) {
    for (int i = 0; i < nb; i++) {
      this.particles.add(new Particle());
    }
  }

  void generate(int nb) {
    for (int i = 0; i < nb; i++) {
      this.particles.add(new Particle());
    }
  }

  void update(int[][] directions, int[][] nextDirections, float t) {
    for (Particle p : particles) {
      int i = (constrain(int(p.position.x), 0, width - 100) / 30) ;
      int j = (constrain(int(p.position.y), 0, height - 100) / 30) ;
      float angle = lerp(directions[i][j], nextDirections[i][j], t) * 0.5 * PI;
      PVector v = new PVector(0.1 * cos(angle), 0.1 * sin(angle));
      p.update(v);
    }
  }

  void recycle() {
    ArrayList<Particle> toRemove = new ArrayList();
    for (Particle p : particles) {
      if (p.isDead()) {
        toRemove.add(p);
      }
    }
    particles.removeAll(toRemove);
  }
}

PSystem ps;


void setup() {
  size(700, 700, P3D);
  smooth(8);
  pixelDensity(displayDensity()); // HiDPI, comment if too slow

  if (isReadyForExport) {
    export = new VideoExport(this, "out.mp4");
    export.setFrameRate(60);
    export.startMovie();
  }

  ps = new PSystem(0);

  nextDirections = getDirections(-1);
  directions = nextDirections;
  rectMode(CENTER);
}

void reset() {
  noStroke();
  background(30);
}

// Taken from https://gist.github.com/gre/1650294
float easeOutQuint(float t) {
  return t<.5 ? 16*pow(t, 5) : 1 + 16 * pow(t-1, 5);
}

void drawLeaf(Particle p) {
  pushMatrix();
  translate(p.position.x - 30, p.position.y - 30, 100 -p.remainingLife() * 3000);
  float n = 10 * frameCount / maxFrameNumber ;
  rotateX((n * TWO_PI + 33 * p.id) % TWO_PI);
  rotateY((n * TWO_PI + 10 * p.id) % TWO_PI);

  fill(255, 255, 255, p.remainingLife() * 255);
  square(0, 0, 60);

  popMatrix();
}


void animation() {
  lights();
  directionalLight(128, 128, 128, 0, 0, 1);  // light from viewer
 
  // current step or "scene". Each does a different animation.
  int step = frameCount / framesPerStep;
  // current frame in the step, so that we can keep track
  float frameInCurrentStep = frameCount % framesPerStep;
  // the current frame normalized [0, framePerStep] => [0, 1]. Makes it easy to apply easings
  float n = frameInCurrentStep / framesPerStep;
  float t = easeOutQuint(n);

  if (frameInCurrentStep == 0) {
    directions = nextDirections;
    nextDirections = getDirections(step);
  }

  translate(width * 0.5, height * 0.5);
  for (Particle p : ps.particles) {
    drawLeaf(p);
  }

  ps.recycle();
  if (frameCount % 4 == 0 && frameCount < (maxFrameNumber - 200)) ps.generate(2);
  ps.update(directions, nextDirections, t);
}

void draw() {
  reset();
  animation();

  if (isReadyForExport) {
    export.saveFrame();
    if (frameCount == 50) saveFrame("screenshot-1.png");
    if (frameCount == Math.floor(maxFrameNumber / 3)) saveFrame("screenshot-2.png");
    if (frameCount == 2 * Math.floor(maxFrameNumber / 3)) saveFrame("screenshot-3.png");
  }

  if (frameCount >= maxFrameNumber) {
    if (isReadyForExport) {
      export.endMovie();
    }
    exit();
  }
}