// 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);
}
}