// click/hold mouse to push Points (dots)
// left/right mouse buttons push/pull
 
Point[] myPts;
 
// Used in the attractor:
float radius = 200, strength = 10;
float ramp = 0.4;    // force ramp-up as it approaches center: 0.01-0.99
float damping = 0.1; // damping of velocity: 0=none, 1=full (default = 0.5)
float maxVelocity = 10;
 
int cols = 51, rows = 51;
float gridSize = 600;
 
void setup() {
  size(800, 800);
  colorMode(RGB, 255, 255, 255, 100);
  smooth();
  cursor(CROSS);
 
  resetPts();
}
 
void resetPts() {
  myPts = new Point[cols*rows];
  int i = 0; // setup node grid
  float rGap = gridSize / (rows - 1);
  float rStart = (height - gridSize) / 2;
  float cGap = gridSize / (cols - 1);
  float cStart = (width - gridSize) / 2;
  for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
      float x = cStart + c * cGap;
      float y = rStart + r * rGap;
      myPts[i] = new Point(x, y);
      i++;
    }
  }
}
 
void draw() {
  background(255);
  for (Point p : myPts) {
    if (mousePressed) { //Attractor with mouse
      p.accelerate(mouseX, mouseY, mouseButton == LEFT);
    }
 
    p.update();
    p.display();
  }
}
 
class Point {
  PVector position = new PVector();
  PVector velocity = new PVector();
 
  public Point(float x, float y) {
    position = new PVector(x, y);
  }
 
  void update() {
    velocity.limit(maxVelocity);
    position.add(velocity);
    velocity.mult(1 - damping);
  }
 
  // accelerates towards or away a target point (tx,ty)
  void accelerate(float tx, float ty, boolean away) {
    PVector dist = new PVector(tx, ty).sub(position);
    // dist in both directions is mouse pos - point pos
 
    // mag: magnitude (size) of dist
    if (0 < dist.mag() && dist.mag() < radius) {
      float s = dist.mag()/radius;  //
      float f = (1 / pow(s, 0.5*ramp) - 1);
      f = strength * f/radius;
 
      if (away) f *= -1;
 
      velocity = velocity.add( dist.mult(f)); // apply force to node velocity
    }
  }
 
  void display() {
    noStroke();
    fill(0);
    rect(position.x, position.y, 3, 3);
  }
}