日常の進捗

主に自分のための,行為とその習慣化の記録

Mod: Coding Challenge #88: Snowfall

f:id:takawo:20171226234343g:plain

Processingで書きながらところどころ自己流で書いた.いわゆるスプライト画像と言われるような,複数の画像がタイル状に配置された1枚の画像を読み込んで適宜使用するようなやり方をやっている.メリークリスマス.

コード

// img src : https://alca.tv/static/f32.png

ArrayList<Snowflake> snow = new ArrayList<Snowflake>();
int num = 1000;
PVector gravity;
ArrayList<PImage> textures = new ArrayList<PImage>();
float zOff = 0;
void setup() {
  size(960, 540);
  colorMode(HSB, 360, 100, 100);
  PImage img = loadImage("f32.png");
  for (int y = 0; y < img.height; y += 32) {
    for (int x = 0; x < img.width; x += 32) {
      textures.add(img.get(x, y, 32, 32));
    }
  }
  gravity = new PVector(0, 0.006);
  for (int i = 0; i < num; i++) {
    snow.add(new Snowflake());
  }
}

void draw() {
  background(0, 0, 0);

  //snow.add(new Snowflake());
  for (Snowflake sf : snow) {
    float xOff = sf.pos.x / width;
    float yOff = sf.pos.y / height;
    float wAngle = noise(xOff, yOff, zOff) * TWO_PI;
    PVector wind = PVector.fromAngle(wAngle);
    wind.mult(0.002);
    sf.applyForce(gravity);
    sf.applyForce(wind);
    sf.update();
    sf.render();
  }
  for (int i = snow.size()-1; i > 0; i--) {
    Snowflake sf = snow.get(i);
    if (sf.isOffScreen()) {
      sf.randomize();
      sf.pos.y = random(-100, -10);
    }
  }
  zOff += 0.01;
}

class Snowflake {
  PVector pos;
  PVector vel;
  PVector acc;
  float r;
  PImage img;
  float angle;
  float dir;
  float freq;
  
  Snowflake() {
    randomize();
  }

  void randomize() {
    r = getRandomSize();
    float x = random(-r, width+r);
    float y = random(-height, height);
    pos = new PVector(x, y);
    vel = new PVector();
    acc = new PVector();
    angle = random(TWO_PI);
    dir = (random(1) > 0.5) ? -1: 1;
    int n = (int)random(textures.size());
    img = textures.get(n);
    freq = random(0.01,0.1);
  }

  void applyForce(PVector force) {
    PVector f = force.copy();
    f.mult(r);
    acc.add(f);
  }

  void update() {
    vel.add(acc);
    vel.limit(r * 0.2);
    if (vel.mag() < 1) {
      vel.normalize();
    }
    pos.add(vel);
    acc.mult(0);
    if (pos.x < -r) {
      pos.x += width+r;
    } else if (pos.x > width + r) {
      pos.x -= width+r;
    }
  }

  void render() {
    //stroke(0, 0, 100);
    //strokeWeight(r);
    //point(pos.x, pos.y);
    pushMatrix();
    translate(pos.x, pos.y);
    rotate(angle+freq*frameCount);
    imageMode(CENTER);
    image(img, 0, 0, r, r);
    popMatrix();
  }

  boolean isOffScreen() {
    return (pos.y > height + r);
  }

  float getRandomSize() {
    /* method 3. */
    float r = pow(random(1), 5);
    return constrain(r * 36, 2, 36);

    /* method 2. */
    //float r = randomGaussian() * 2;
    //return constrain(abs(r*r), 2, 36);

    /* method 1. */
    //while (true) {
    //  float r1 = random(1);
    //  float r2 = random(1);
    //  if (r2 > r1) {
    //    return r1 * 36;
    //  }
    //}
  }
}

リファレンス

www.youtube.com