Daily Creative Coding

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

反発・誘引するパーティクル

同じ色のパーティクルは反発する. 違う色のパーティクルは引き付け合う.

JavaScriptモードでは重すぎて動かない.

/**
* Two Color Particles
*
* Particles with same color repel each other, particles with different color attract each other.
*
* @author aa_debdeb
* @date 2015/10/02
*/

float PARTICLE_RADIOUS = 3.0;
float PARTICLE_NUM = 500;
float MAX_FORCE = 1.0;
float MAX_ACCELERATION = 3.0;
float MAX_VELOCITY = 5.0;
float VIEW_DISTANCE = 100;

ArrayList<Particle> particles;

void setup(){
  size(500, 500);
  smooth();
  frameRate(24);
  noFill();
  
  particles = new ArrayList<Particle>();
  for(int i = 0; i < PARTICLE_NUM; i++){
    particles.add(new Particle());
  }
}

void draw(){
  background(0);
  for(Particle particle : particles){
    particle.draw();
  }
  for(Particle particle : particles){
    particle.update();
  }
}


class Particle{
  PVector position;
  PVector velocity;  
  boolean isRed;
  
  Particle(){
    position = new PVector(random(width), random(height));
    velocity = new PVector(0.0, 0.0);
    isRed = random(1) < 0.5 ? true : false;
  }
  
  void draw(){
    if(isRed){
      stroke(255, 0, 0);
    } else {
      stroke(0, 255, 0);
    }
    ellipse(position.x, position.y, PARTICLE_RADIOUS * 2, PARTICLE_RADIOUS * 2);
  }
  
  void update(){
    PVector acceleration = new PVector(0, 0);
    for(Particle particle: particles){
      if(particle != this){
        float relativeX = particle.position.x - position.x;
        float relativeY = particle.position.y - position.y;
        if(relativeX > width / 2){
          relativeX = relativeX - width;
        } else if(relativeX < -width / 2){
          relativeX = width + relativeX;
        }
        if(relativeY > height / 2){
          relativeY = relativeY - height;
        } else if(relativeY < -height / 2){
          relativeY = height + relativeY;
        }
        PVector relativePosition = new PVector(relativeX, relativeY);
        float distance = relativePosition.mag();
        if(distance < VIEW_DISTANCE){
          PVector a;
          float force = (VIEW_DISTANCE - distance) / VIEW_DISTANCE * MAX_FORCE;
          float relativeAngle = relativePosition.heading();       
          if(isRed == particle.isRed){
            a = new PVector(force * cos(relativeAngle + PI), force * sin(relativeAngle + PI));
          } else {
            a = new PVector(force * cos(relativeAngle), force * sin(relativeAngle));
          }          
          acceleration.add(a);   
        }
      }
    }
    if(acceleration.mag() > MAX_ACCELERATION){
      acceleration.normalize();
      acceleration.mult(MAX_ACCELERATION);
    }
    velocity.add(acceleration);
    if(velocity.mag() > MAX_VELOCITY){
      velocity.normalize();
      velocity.mult(MAX_VELOCITY);
    }
    position.add(velocity);
    if(position.x >= width){
      position.x -= width;
    } else if(position.x < 0){
      position.x += width;
    }
    if(position.y >= height){
      position.y -= height;
    } else if(position.y < 0){
      position.y += height;
    }
  }
  
}