> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.vb3yvpw2NUJ/rev.368
 * 
 * authors: 
 *   Farshid Naderi
 *   Sina Seifee

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



// left   click "Hate" ball.
// right  click "Love" ball.
// middle click kill all balls.
// click  and drag for move balls.

Ball[] balls = new Ball[0];

int   grab = -1;
float time =0.0;

void setup() {
    size(400,400);
    smooth();
    frameRate(25);
    background(255);
    for (int i=0; i<2; i++;){
        makeNewBall("hate", random(width),random(height), random(5, 35));
        makeNewBall("love", random(width),random(height), random(5, 35));
    }
}

void draw() {
    //background(20);
    cursor(CROSS);
  
    if(mousePressed == true){
      selectBall();  
      if(grab>=0){
        balls[grab].mouseMove();
      }else{
        if(mouseButton == LEFT)
          makeNewBall("hate",mouseX, mouseY, random(5, 35) );
        if(mouseButton == RIGHT)
          makeNewBall("love",mouseX, mouseY, random(5, 35) );
        if(mouseButton == CENTER)
          balls = new Ball[0];
        grab = balls.length-1;
      
      }   
    }
    
    for (int i = 0; i < balls.length; i = i+1) {
      connectBall(i); 
    }
    
    for (int i = 0; i < balls.length; i = i+1) {
      if(i!=grab) balls[i].drag();
      balls[i].display();
    }
    time+=1.01;
}

void mouseReleased() {
    
    grab = -1;
}

void connectBall(int id) {

    PVector push = new PVector(0,0);
    PVector run  = new PVector(0,0);
    float   dis  = 0.0;
    for (int i = 0; i < balls.length; i = i+1) {

      if(i!=id && dist(balls[i].pos.x,balls[i].pos.y,balls[id].pos.x,balls[id].pos.y)< balls[id].rad*5 ){
        stroke(balls[id].col);
        
        if(random(5)<1)
          nLine(balls[i].pos.x, balls[i].pos.y, balls[id].pos.x, balls[id].pos.y, id+i, 10);
        if(random(10)<1)
          nLine(balls[i].pos.x, balls[i].pos.y, balls[id].pos.x, balls[id].pos.y, id+i+5, 10);
        if(random(15)<1)
          nLine(balls[i].pos.x, balls[i].pos.y, balls[id].pos.x, balls[id].pos.y, id+i-5, 10);
        
        dis = PVector.dist(balls[i].pos,balls[id].pos);
        dis = norm(dis, balls[id].rad*5, 0); 
        
        if(balls[id].mode == "love") 
          run = PVector.sub(balls[i].pos,balls[id].pos);
        if(balls[id].mode == "hate") 
          run = PVector.sub(balls[id].pos,balls[i].pos);
        
        run.limit(2);
        run.mult(dis);
      }
      
      if(i!=id && dist(balls[i].pos.x,balls[i].pos.y,balls[id].pos.x,balls[id].pos.y)< balls[i].rad*5 ){
        dis = PVector.dist(balls[i].pos,balls[id].pos);
        dis = norm(dis, balls[i].rad*5, 0); 
        
        if(balls[id].mode == "love") 
          push = PVector.sub(balls[i].pos,balls[id].pos);
        if(balls[id].mode == "hate") 
          push = PVector.sub(balls[id].pos,balls[i].pos);
        
        push.limit(4);
        push.mult(dis);
      }
    }
    run.add(push);
    run.mult(balls[id].mass);
    balls[id].influ = run;

}

void selectBall() {
  if(grab==-1){ 
    for (int i = 0; i < balls.length; i = i+1) {
      if(dist(balls[i].pos.x,balls[i].pos.y,mouseX,mouseY) < balls[i].rad/2 ){
        grab = balls[i].ID;
      }       
    }
  }
}

void makeNewBall(String mode, float x, float y, float rad) {
    
    Ball newBall = new Ball(mode, balls.length , x, y, rad); 
    balls = (Ball[]) append(balls,newBall);
}



/////////////////////////////////////////
//---Noise Line
void nLine(float startX, float startY, float endX, float endY, float timeOffset, int pointCount){
    
    noFill(); 
    pointCount++;
    float xDis = norm((startX-endX),0,width);
    float yDis = norm((startY-endY),0,height)*-1;
    float timeLine = time+timeOffset;
    beginShape();
    curveVertex(startX, startY); // control point  (first)
    curveVertex(startX, startY); // point of curve (first)
    
    for (float i = 1.0; i < pointCount; i++) {
      float step = i/pointCount;
      
      float xMid = lerp(startX, endX,step);
      float yMid = lerp(startY, endY,step);
      
      float smoothing = (i<pointCount/2) ? step : (1-step);
      
      float xNois= ( ( (noise(timeLine) )*2) -1)*yDis*smoothing*100;
      float yNois= ( ( (noise(timeLine) )*2) -1)*xDis*smoothing*100;

      curveVertex(xMid+xNois, yMid+yNois); //mid control point 
      
      //float rad = abs(sin(time))*5;
      //ellipse(xMid+xNois, yMid+yNois, rad, rad);
      
      timeLine += pointCount/pointCount;
    }
    curveVertex(endX, endY);   // point of curve (last)
    curveVertex(endX, endY);   // control point  (last)
    endShape(); 
}
/////////////////////////////////////////


/////////////////////////////////////////
//// start class Ball ///////////////////
//
class Ball { 
  
  PVector pos;
  PVector direct;
  PVector influ;
  String  mode;
  color   col;
  float   speed;
  float   rad;
  float   mass;
  int     ID;

  Ball(String ballBode, int ballID, float posx, float posy, float ballRad) { 
    ID    = ballID;  
    mode  = ballBode;
    pos   = new PVector(posx, posy);
    direct= new PVector(0,0);
    influ = new PVector(0.0,0.0);
    rad   = ballRad;
    mass  = map(rad, 35, 5, 1.1, 1.999);
    
    if(mode == "love")  
      col  = color(random(150,255), random(10,100), random(100,110));
    if(mode == "hate")
      col  = color(random(20,50), random(50,255), random(50,255));

  }

  void display() {
    stroke(255);
    fill(col);
    ellipse(pos.x,pos.y,rad,rad);
    
    stroke(col,25);
    fill(col,10);
    //ellipse(pos.x,pos.y,rad*10,rad*10);
  }

  void mouseMove() {
    pos.x = mouseX;
    pos.y = mouseY;
    direct.x = mouseX-pmouseX;
    direct.y = mouseY-pmouseY;  
  }
  
  void drag() {

    direct.add(influ);
    direct.mult(0.85);
    pos.add(direct);
    
    if (pos.x < 0){ 
      direct.x *= -1;
      pos.x = 1; 
    }
    if(pos.x > width){
      direct.x *= -1;
      pos.x = width-1;
    }
    
    if (pos.y < 0){ 
      direct.y *= -1;
      pos.y = 1; 
    }
    if(pos.y > height){
      direct.y *= -1;
      pos.y = height-1;
    }

  }

}

//
///////////////////// end class Ball ////
/////////////////////////////////////////