読者です 読者をやめる 読者になる 読者になる

30 min. Processing

毎日30分、Processingで何かを作る

パーティクル同士の衝突と反射

物理
/**
* collision with many particles and walls
*
* @author aa_debdeb
* @date 2017/01/04
*/

float e = 0.5;
float k = 0.3;

ArrayList<Particle> particles;

void setup(){
  size(500, 500);
  noStroke();
  frameRate(30);
  particles = new ArrayList<Particle>();
  while(particles.size() < 50){
    float radius = random(5, 30);
    PVector loc = new PVector(random(radius, width - radius), random(radius, height - radius));
    boolean isOverlapping = false;
    for(Particle p: particles){
      if(PVector.dist(loc, p.loc) <= radius + p.radius){
        isOverlapping = true;
        break;
      }
    }
    if(!isOverlapping){
      float velSize = 5.0;
      float velAng = random(TWO_PI);
      PVector vel = new PVector(velSize * cos(velAng), velSize * sin(velAng));
      particles.add(new Particle(loc, vel, radius));
    }
  }  
}

void draw(){
  background(#007FB1);
  for(Particle p: particles){
    p.render();
    p.move();
  }
  
  for(Particle p: particles){
    p.reflectFromWalls();
  }
    
  for(Particle p1: particles){
    for(Particle p2: particles){
      if(p1 == p2){continue;}
      p1.addImpulse(p2);
    }
  }
  
  for(Particle p: particles){
    p.updateVel();
  }
  
}

class Particle{
  
  PVector loc, vel, nvel;
  float radius, mass;
  color c;
  
  Particle(PVector loc, PVector vel, float radius){
    this.loc = loc;
    this.vel = vel;
    this.nvel = new PVector(vel.x, vel.y);
    this.radius = radius;
    this.mass = 1.0;
    if(radius < 15){
      c = color(#AEC1E3);
    } else {
      c = color(#95DFD6);
    }
  }
  
  void move(){
    loc.add(vel);
  }
  
  void render(){
    fill(c);
    ellipse(loc.x, loc.y, radius * 2, radius * 2);
  }
  
  void reflectFromWalls(){
    if(loc.x < radius){
      reflectFromWall(new PVector(1, 0));  
    }
    if(loc.x > width - radius){
      reflectFromWall(new PVector(-1, 0));        
    }
    if(loc.y < radius){
      reflectFromWall(new PVector(0, 1));  
    }
    if(loc.y > height - radius){
      reflectFromWall(new PVector(0, -1));        
    }   
  }
  
  void reflectFromWall(PVector n){
    PVector vn = PVector.mult(n, PVector.dot(vel, n));
    PVector vt = PVector.sub(vel, vn);
    vel = PVector.add(PVector.mult(vn, -1), vt);
    nvel = new PVector(vel.x, vel.y);
    loc.add(vel);
  }
  
  void addImpulse(Particle p){
    float d = PVector.dist(loc, p.loc);
    if(d <= radius + p.radius){
      PVector pDiff = PVector.sub(p.loc, loc);
      PVector n = PVector.div(pDiff, pDiff.mag());
      PVector vDiff = PVector.sub(p.vel, vel);
      float spring = -k * (radius + p.radius - d);
      float j = (1 + e) * (mass * p.mass / (mass + p.mass)) * PVector.dot(vDiff, n);
      PVector impulse = PVector.mult(n, j + spring); 
      nvel.add(impulse);  
    }
  }
  
  void updateVel(){
    vel = nvel;
    nvel = new PVector(vel.x, vel.y);
  }
}
f:id:aa_debdeb:20161230140429j:plain