日常の進捗

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

Mod:Coding Challenge #56: Attraction and Repulsion Forces

引力と斥力をシミュレーションする.このへんはNature of Codeに書かれてたのでなんとなく手癖で書ける部分がある.アトラクターがパーティクルを引っ張る力を持っていて,そいつに近づきすぎると今度は斥力を発生させて,これまで引っ張っていた力を反転させる.マウスをクリックしたらアトラクターが発生するようにした.あとはそれぞれのパーティクルに寿命を設定して,ライフがゼロになると消えるようにした.

The Nature of Code

関係ないけど,最近ブログに貼り付けたコードが長くなってきた分,読みづらい気がするので,以下の記事を参考にコードに行数を表示するようにした.読みやすくなったと思う.

追記:3D版も作った.こういうところがPVectorのいいところ.

am1tanaka.hatenablog.com

コード(2D版)

ArrayList<Particle> attractors = new ArrayList<Particle>();
ArrayList<Particle> particles = new ArrayList<Particle>();

float offset =50;

void setup() {
  fullScreen();
  colorMode(HSB, 360, 100, 100, 100);
  for (int i = 0; i < 10; i++) {
    float x = random(width);
    float y = random(height);
    Particle attractor = new Particle(x, y, true);
    attractors.add(attractor);
  }
  background(302, 62, 18);
}

void draw() {
  noStroke();
  fill(302, 62, 18, 5);
  rect(0, 0, width, height);
  for (Particle attractor : attractors) {
    attractor.update();
    attractor.draw();
  }

  for (Particle particle : particles) {
    for (Particle attractor : attractors) {
      particle.attracted(attractor);
    }
    particle.update();
    particle.draw();
  }

  if (random(1) > 0.9) {
    Particle p = new Particle(random(width), random(height));
    particles.add(p);
  }

  for (int i = attractors.size()-1; i >= 0; i--) {
    Particle attractor = attractors.get(i);
    if (attractor.life < 0) {
      attractors.remove(i);
      attractors.add(new Particle(random(width), random(height), true));
    }
  }
  for (int i = particles.size()-1; i >= 0; i--) {
    Particle particle = particles.get(i);
    if (particle.life < 0 && particles.size() > 100) {
      particles.remove(i);
      particles.add(new Particle(random(width), random(height)));
    }
  }

  for (Particle particle : particles) {
    for (Particle attractor : attractors) {
      particle.attracted(attractor);
    }
    particle.update();
    particle.draw();
  }
}

void mousePressed() {
    Particle attractor = new Particle(mouseX, mouseY, true);
    attractors.add(attractor);
}

class Particle {

  PVector pos, prev, vel, acc;
  boolean isAttractor = false;
  float life, lifeSpan;

  Particle(float _x, float _y) {
    pos = new PVector(_x, _y);
    prev = new PVector(_x, _y);
    vel = new PVector();
    acc = new PVector();
    life = random(1.5, 3);
    lifeSpan = random(life/300, life/150);
  }
  Particle(float _x, float _y, boolean _isAttractor) {
    pos = new PVector(_x, _y);
    prev = new PVector(_x, _y);
    vel = new PVector();
    acc = new PVector();
    isAttractor = _isAttractor;
    life = random(1.5, 3);
    lifeSpan = random(life/300, life/150);
  }

  void update() {
    vel.add(acc);
    vel.limit(5);
    pos.add(vel);
    acc.mult(0);
    life -= lifeSpan;
  }

  void draw() {
    if (isAttractor) {
      stroke(337, 98, 51);
      strokeWeight(16);
    } else {
      stroke(191, 93, 81);
      strokeWeight(4);
    }
    line(pos.x, pos.y, prev.x, prev.y);
    prev.x = pos.x;
    prev.y = pos.y;
  }

  void attracted(Particle target) {
    PVector force = PVector.sub(target.pos, pos);
    float mag = force.mag();
    mag = constrain(mag, 1, 25);
    float g = 50;
    float strength = g / (mag * mag);
    force.setMag(strength);
    if (mag < 25) {
      force.mult(-10);
    }
    acc.add(force);
  }
}

コード(3D版)

ArrayList<Particle> attractors = new ArrayList<Particle>();
ArrayList<Particle> particles = new ArrayList<Particle>();

float offset =50;

void setup() {
  fullScreen(P3D);
  colorMode(HSB, 360, 100, 100, 100);
  for (int i = 0; i < 10; i++) {
    float x = random(-width/2, width/2);
    float y = random(-height/2, height/2);
    float z = random(-500, 500);
    Particle attractor = new Particle(x, y, z, true);
    attractors.add(attractor);
  }
  background(302, 62, 18);
}

void draw() {
  //noStroke();
  //fill(302, 62, 18, 5);
  //rect(0, 0, width, height);
  background(302, 62, 18);
  pushMatrix();
  translate(width/2, height/2, -1000);
  rotateY(frameCount*0.01);
  rotateZ(PI/7);
  for (Particle attractor : attractors) {
    attractor.update();
    attractor.draw();
  }

  for (Particle particle : particles) {
    for (Particle attractor : attractors) {
      particle.attracted(attractor);
    }
    particle.update();
    particle.draw();
  }

  if (random(1) > 0.9) {
    float x = random(-width/2, width/2);
    float y = random(-height/2, height/2);
    float z = random(-500, 500);
    Particle p = new Particle(x, y, z);
    particles.add(p);
  }

  for (int i = attractors.size()-1; i >= 0; i--) {
    Particle attractor = attractors.get(i);
    if (attractor.life < 0) {
      attractors.remove(i);
      float x = random(-width/2, width/2);
      float y = random(-height/2, height/2);
      float z = random(-500, 500);

      attractors.add(new Particle(x, y, z, true));
    }
  }
  for (int i = particles.size()-1; i >= 0; i--) {
    Particle particle = particles.get(i);
    if (particle.life < 0 && particles.size() > 100) {
      particles.remove(i);
      float x = random(-width/2, width/2);
      float y = random(-height/2, height/2);
      float z = random(-500, 500);

      particles.add(new Particle(x, y, z));
    }
  }

  for (Particle particle : particles) {
    for (Particle attractor : attractors) {
      particle.attracted(attractor);
    }
    particle.update();
    particle.draw();
  }
  popMatrix();
}

void mousePressed() {
  Particle attractor = new Particle(mouseX, mouseY, random(-500, 500), true);
  attractors.add(attractor);
}

class Particle {

  PVector pos, prev, vel, acc;
  boolean isAttractor = false;
  float life, lifeSpan;

  Particle(float _x, float _y, float _z) {
    pos = new PVector(_x, _y, _z);
    prev = new PVector(_x, _y, _z);
    vel = new PVector();
    acc = new PVector();
    life = random(1.5, 3);
    lifeSpan = random(life/300, life/150);
  }
  Particle(float _x, float _y, float _z, boolean _isAttractor) {
    pos = new PVector(_x, _y, _z);
    prev = new PVector(_x, _y, _z);
    vel = new PVector();
    acc = new PVector();
    isAttractor = _isAttractor;
    life = random(1.5, 3);
    lifeSpan = random(life/300, life/150);
  }

  void update() {
    vel.add(acc);
    vel.limit(5);
    pos.add(vel);
    acc.mult(0);
    life -= lifeSpan;
  }

  void draw() {
    pushMatrix();
    translate(pos.x, pos.y, pos.z);
    if (isAttractor) {
      fill(337, 98, 51);
      noStroke();
      box(16);
    } else {
      fill(191, 93, 81);
      noStroke();
      box(4);
    }
    popMatrix();
    prev.x = pos.x;
    prev.y = pos.y;
    prev.z = pos.z;
  }

  void attracted(Particle target) {
    PVector force = PVector.sub(target.pos, pos);
    float mag = force.mag();
    mag = constrain(mag, 1, 25);
    float g = 50;
    float strength = g / (mag * mag);
    force.setMag(strength);
    if (mag < 25) {
      force.mult(-10);
    }
    acc.add(force);
  }
}

リファレンス