Processing : パーティクル同士の衝突判定

collide()関数の中に全てが詰まっています。

```java:Particle.pde
class Particle
{
  PVector pos;
  PVector vel;
  float   damping;
  float   radius;
  float   startTime, lifeSpan;
  color   col;
  float   alpha;
  boolean dead;
  
  // constructor
  Particle( float _x, float _y, float _r, color _c )
  {
    pos    = new PVector( _x, _y );
    radius = _r;
    
    float strength = 0.1;
    float angle    = random( TWO_PI );
    vel            = new PVector( ( cos( angle ) * strength ), ( sin( angle ) * strength ) );
    
    damping        = 0.6;
    
    // birth time
    startTime = millis();
    
    // lifespan ( 10sec ~ 30sec )
    lifeSpan  = random( 10000, 30000 );
    
    col       = _c;
    alpha     = 255;
    dead      = false;
  }
  
  // update
  void update()
  {
    // add gravity
//    vel.y += 0.2;
//    vel.y *= 1.002;
    
    // decelerate
    vel.mult( 0.99 );
    
    // update position
    pos.add( vel );
    
    // bounce off
    if( pos.x < radius )
    {
      pos.x += abs( pos.x - radius );
      vel.x *= -damping;
    }
    else if( pos.x > ( width - radius ) )
    {
      pos.x -= ( pos.x - ( width - radius ) );
      vel.x *= -damping;
    }
    if( pos.y < radius )
    {
      pos.y += abs( pos.y - radius );
      vel.y *= -damping;
    }
    else if( pos.y > ( height - radius ) )
    {
      pos.y -= ( pos.y - ( height - radius ) );
      vel.y *= -damping;
    }
    
    // over the lifespan
    if( millis() > ( startTime + lifeSpan ) )
    {
      dead = true;
//      alpha -= ( alpha / 10 );
//      
//      if( alpha < 1 )
//      {
//        dead = true;
//      }
    }
  }
  
  // draw
  void draw()
  {
    fill( col, alpha );
    ellipse( pos.x, pos.y, ( radius * 2 ), ( radius * 2 ) );
  }
}
```

```java:collisionOfParticles.pde
// ArrayList of particle
ArrayList< Particle > ps;

////////////////////////////////////////
// setup
////////////////////////////////////////
void setup()
{
  // set window size, and set renderer P2D
  size( 400, 400, P2D );
  
  // for fullscreen ( command + shift + R )
//  size( displayWidth, displayHeight, P2D );
  
  // enable resizing the window
  frame.setResizable( true );
  
  // enable smoothing
  smooth();
  
  // set color mode HSB
  colorMode( HSB, 255 );
  
  background( 255 );
  
  // create instance of ArrayList
  ps = new ArrayList< Particle >();
}


////////////////////////////////////////
// draw
////////////////////////////////////////
void draw()
{
  background( 255 );
  noStroke();
  
  // add a particle
  if( mousePressed )
  {
    ps.add( new Particle( mouseX, mouseY, random( 4, 10 ), color( ( frameCount * 0.1 ) % 255,  120, 255 ) ) );
  }
  
  // update particle position
  for( Particle p : ps )
  {
    p.update();
  }
  
  // collision of particles
  collide();
  
  // remove and draw particles
  for( int i = ( ps.size() - 1 ); i >= 0; --i )
  {
    Particle p = ps.get( i );
    
    if( p.dead )
    {
      ps.remove( i );
    }
    
    p.draw();
  }
}




////////////////////////////////////////
// collide
////////////////////////////////////////
void collide()
{
  for( int i = 0; i < ps.size(); ++i )
  {
    for( int j = ( i + 1 ); j < ps.size(); ++j )
    {
      Particle p1 = ps.get( i );
      Particle p2 = ps.get( j );
      
      // vector from p1 to p2
      PVector diff   = PVector.sub( p2.pos, p1.pos );
      
      // distance from p1 to p2
      float dist     = diff.mag();
      
      // correct distance
      float shortest = ( p1.radius + p2.radius );
      
      if( dist < shortest )
      {
        diff.normalize();
        diff.mult( ( shortest - dist ) * 0.5 );
        
        PVector v1 = diff.get();
        PVector v2 = PVector.mult( diff.get(), -1 );
        
        // move to the correct position
        p1.pos.add( v2 );
        p2.pos.add( v1 );
        
        // scale down the velocity
        float vScale = 0.4;
        PVector vv1  = PVector.mult( v1.get(), vScale );
        PVector vv2  = PVector.mult( v2.get(), vScale );
        
        // add velocity
        p1.vel.add( vv2 );
        p2.vel.add( vv1 );
      }
    }
  }
}




////////////////////////////////////////
// mousePressed
////////////////////////////////////////
void mousePressed()
{
  
}


////////////////////////////////////////
// keyPressed
////////////////////////////////////////
void keyPressed()
{
  if( key == ' ' )
  {
    // clear particles
    ps.clear();
  }
}
```

gravityを有効にすると荒ぶってしまうのはどうしてだろう。。