xxxxxxxxxx
320
var myParticles = [];
var mySprings = [];
var colliders = [];
var dropX = 30;
var dropY = 30;
var dropR = 50;
var buttonCol = 255;
var dropBool = false;
var master = []; //holds all spring lines
var drawing = false;
// The index in the particle array, of the one the user has clicked.
var whichParticleIsGrabbed = -1;
//-------------------------
function setup() {
createCanvas(640, 480);
for (var i = 1; i < 5; i++) {
var newBox = makeCollider(random(50, width - 50), random(50, height - 50), random(40, 100), 10);
colliders.push(newBox);
}
}
//-------------------------
function createParticles(rx, ry, rc) { //make a particle for each point in each line
var aParticle = new Particle();
aParticle.set(rx, ry, rc);
aParticle.bPeriodicBoundaries = false;
aParticle.bHardBoundaries = true;
myParticles.push(aParticle);
}
//-------------------------
function createSpringMeshConnectingParticles() {
// Stitch the particles together into a mesh,
// by connecting them to their neighbors with springs.
// The spring constant.
var K = 0.005;
// stitch the particles together into a blob.
for (var i = 0; i < master.length; i++) {
for (var j = 0; j < master[i].length - 1; j++) {
var p = master[i][j];
var q = master[i][j + 1];
var aSpring = new Spring();
aSpring.set(p, q, K);
mySprings.push(aSpring);
}
}
}
function mousePressed() {
// If the mouse is pressed,
// find the closest particle, and store its index
if (keyIsDown(SHIFT)) {
whichParticleIsGrabbed = -1;
var maxDist = 9999;
for (var i = 0; i < myParticles.length; i++) {
var dx = mouseX - myParticles[i].px;
var dy = mouseY - myParticles[i].py;
var dh = sqrt(dx * dx + dy * dy);
if (dh < maxDist) {
maxDist = dh;
whichParticleIsGrabbed = i;
}
}
}
}
function draw() {
background(102);
fill(255);
noStroke();
for (var b = 0; b < colliders.length; b++) {
// rect(this.x, this.y, this.w, this.h);
rect(colliders[b].x1, colliders[b].y1, colliders[b].w, colliders[b].h);
}
if (!mouseIsPressed) drawing = false;
buttonStuff();
for (var a = 0; a < master.length; a++) {
beginShape();
noFill();
// stroke(a * 50);
strokeWeight(10);
if (master[a].length > 0) vertex(master[a][0].px, master[a][0].py);
for (var b = 0; b < master[a].length; b++) {
var p = master[a][b];
stroke(p.col);
//p.render(); // draw all particles
curveVertex(p.px, p.py);
}
//vertex at line's last point
if (master[a].length > 0) vertex(master[a][master[a].length - 1].px, master[a][master[a].length - 1].py);
endShape();
}
}
function buttonStuff() {
noStroke();
if (!dropBool) {
fill(buttonCol);
ellipse(dropX, dropY, dropR, dropR);
fill(map(buttonCol, 0, 255, 255, 0));
dropButtonDist = dist(dropX, dropY, mouseX, mouseY);
text("DROP", dropX - 17, dropY + 5);
if (mouseIsPressed && dropButtonDist < dropR) {
buttonCol = 0;
dropBool = true;
}
} else { //if (dropBool) {
drop();
fill(255);
text("Pick your spaghetti off the floor!", dropX - 17, dropY);
text("Hold shift and drag to pick up lines", dropX - 17, dropY + 15);
}
}
var newColor = [100, 100, 100];
function mouseDragged() {
if (!keyIsDown(SHIFT)) {
if (!drawing) {
master[master.length] = []; //create array to hold new line
newColor = [random(100, 255), random(100, 255), random(100, 255)];
}
drawing = true;
var tooClose = false;
for (var i = 0; i < myParticles.length; i++) {
var p = myParticles[i];
var d = dist(mouseX, mouseY, p.px, p.py);
if (d < 10) tooClose = true;
}
if (!tooClose) {
createParticles(mouseX, mouseY, newColor);
master[master.length - 1].push(myParticles[myParticles.length - 1]);
createSpringMeshConnectingParticles();
}
}
}
//==========================================================
function makeCollider(x, y, w, h) {
var collider = {
x1: x,
y1: y,
w: w,
h: h,
x2: x + w,
y2: y + h
};
return collider;
}
//==========================================================
function drop() {
if (mouseIsPressed && (whichParticleIsGrabbed > -1) && keyIsDown(SHIFT)) {
// If the user is grabbing a particle, peg it to the mouse.
myParticles[whichParticleIsGrabbed].px = mouseX;
myParticles[whichParticleIsGrabbed].py = mouseY;
}
for (var i = 0; i < myParticles.length; i++) {
myParticles[i].update(); // update all locations
}
var gravityForceX = 0;
var gravityForceY = 0.3;
for (var i = 0; i < myParticles.length; i++) {
myParticles[i].addForce(gravityForceX, gravityForceY);
}
for (var i = 0; i < mySprings.length; i++) {
mySprings[i].update(); // update all springs
}
for (var i = 0; i < mySprings.length; i++) {
mySprings[i].render(); // draw all springs
}
}
//==========================================================
var Particle = function Particle() {
this.px = 0;
this.py = 0;
this.vx = 0;
this.vy = 0;
this.mass = 1.0;
this.damping = 0.96;
this.bFixed = false;
this.bLimitVelocities = true;
this.bPeriodicBoundaries = false;
this.bHardBoundaries = false;
// Initializer for the Particle
this.set = function(x, y, c) {
this.px = x;
this.py = y;
this.vx = 0;
this.vy = 0;
this.damping = 0.96;
this.mass = 1.0;
this.col = c;
};
// Add a force in. One step of Euler integration.
this.addForce = function(fx, fy) {
var ax = fx / this.mass;
var ay = fy / this.mass;
this.vx += ax;
this.vy += ay;
};
// Update the position. Another step of Euler integration.
this.update = function() {
if (this.bFixed == false) {
this.vx *= this.damping;
this.vy *= this.damping;
this.limitVelocities();
this.handleBoundaries();
this.px += this.vx;
this.py += this.vy;
}
};
this.limitVelocities = function() {
if (this.bLimitVelocities) {
var speed = sqrt(this.vx * this.vx + this.vy * this.vy);
var maxSpeed = 10;
if (speed > maxSpeed) {
this.vx *= maxSpeed / speed;
this.vy *= maxSpeed / speed;
}
}
};
this.handleBoundaries = function() {
if (this.bPeriodicBoundaries) {
if (this.px > width) this.px -= width;
if (this.px < 0) this.px += width;
if (this.py > height) this.py -= height;
if (this.py < 0) this.py += height;
} else if (this.bHardBoundaries) {
if (this.px >= width) {
this.vx = abs(this.vx) * -1;
}
if (this.px <= 0) {
this.vx = abs(this.vx);
}
if (this.py >= height) {
this.vy = abs(this.vy) * -1;
}
if (this.py <= 0) {
this.vy = abs(this.vy);
}
for (var i = 0; i < colliders.length; i++) {
var box = colliders[i];
if (this.px >= box.x1 - 10 && this.px <= box.x2 + 10 && this.py <= box.y1 && this.py >= box.y1 - 10) this.vy = abs(this.vy) * -1;
}
}
};
this.render = function() {
//fill(255);
ellipse(this.px, this.py, 9, 9);
};
}
//==========================================================
var Spring = function Spring() {
var p;
var q;
var restLength;
var springConstant;
this.set = function(p1, p2, k) {
p = p1;
q = p2;
var dx = p.px - q.px;
var dy = p.py - q.py;
restLength = sqrt(dx * dx + dy * dy);
springConstant = k;
};
this.update = function() {
var dx = p.px - q.px;
var dy = p.py - q.py;
var dh = sqrt(dx * dx + dy * dy);
if (dh > 1) {
var distention = dh - restLength;
var restorativeForce = springConstant * distention; // F = -kx
var fx = (dx / dh) * restorativeForce;
var fy = (dy / dh) * restorativeForce;
p.addForce(-fx, -fy);
q.addForce(fx, fy);
}
};
this.render = function() {
line(p.px, p.py, q.px, q.py);
};
}