Daily Creative Coding

元「30 min. Processing」。毎日、Creative Codingします。

誘引・反発されるパーティクルの軌跡

/**
* drawing by attractor and repulser
*
* @author aa_debdeb
* @date 2016/03/17
*/

float G = 1.0;

ArrayList<Particle> particles;
ArrayList<Attractor> attractors;

void setup(){
  size(640, 640);
  frameRate(120);
  
  particles = new ArrayList<Particle>();
  for(int i = 0; i < 300; i++){
    particles.add(new Particle());
  }
  
  attractors = new ArrayList<Attractor>();
  for(int i = 0; i < 100; i++){
    attractors.add(new Attractor());
  }
  
  strokeWeight(1);
  stroke(0, 10);
  
  background(255);
}

void draw(){
  
  for(Particle particle: particles){
    for(Attractor attractor: attractors){
      PVector force = attractor.calcForce(particle);
      particle.addForce(force);
    }    
    particle.update();
    if(random(1) < 0.005){
      particle.setRandomPosVel();
    }
  }
}

class Particle {

  PVector pos, vel, force;
  float mass;
  
  Particle(){
    setRandomPosVel();
    force = new PVector(0, 0);
    mass = map(random(1), 0, 1, 0.05, 0.1);
  }
  
  void setRandomPosVel(){
    pos = new PVector(random(width), random(height));
    float velSize = map(random(1), 0, 1, 1, 3);
    float velAng = random(TWO_PI);
    vel = new PVector(velSize * cos(velAng), velSize * sin(velAng));
  }
  
  void addForce(PVector f){
    force.add(f);
  }
  
  void update(){
    force.limit(1);
    PVector acc = PVector.mult(force, mass);
    acc.limit(1);
    vel.add(acc);
    vel.limit(3);
    PVector nPos = PVector.add(pos, vel);
    line(pos.x, pos.y, nPos.x, nPos.y);
    if(nPos.x >= 0 && nPos.x < width && nPos.y >= 0 && nPos.y < height){
      pos = nPos;
    } else {
      setRandomPosVel();
    }
    force = new PVector(0, 0); 
  }
 
}

class Attractor {
  
  PVector pos;
  float mass;
  float radious;
  boolean isAttract;
  
  Attractor(){
    pos = new PVector(random(width), random(height));
    mass = map(random(1), 0, 1, 50, 500);
    radious = map(random(1), 0, 1, 100, 500);
    isAttract = random(1) < 0.5 ? true: false;
  }
  
  PVector calcForce(Particle particle){
    float distance = PVector.dist(pos, particle.pos);
    if(distance < radious){
      float forceSize = (G * (mass * particle.mass)) / sq(map(distance, 0,  radious, 0.00000001, 1));
      PVector forceAng = isAttract ? PVector.sub(particle.pos, pos) : PVector.sub(particle.pos, pos); 
      forceAng.normalize();
      PVector force = PVector.mult(forceAng, forceSize);
      return  force;
    } else {
      return new PVector(0, 0);
    }
  }
}