xxxxxxxxxx
238
var myParticles = [];
var mySprings = [];
var nPoints;
// The index in the particle array, of the one the user has clicked.
var whichParticleIsGrabbed = -1;
//-------------------------
function setup() {
createCanvas(600, 400);
createParticles();
createSpringMeshConnectingParticles();
}
//-------------------------
function createParticles(){
nPoints = 47;
var radius = 100;
for (var i=0; i<nPoints; i++) {
var t = map(i, 0,nPoints, 0,TWO_PI);
var rx = width/2 + radius * cos(t);
var ry = height/2 + radius * sin(t);
var aParticle = new Particle();
aParticle.set(rx,ry);
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.1;
// stitch the particles together into a blob.
for (var i=0; i<(nPoints/2); i++) {
var p = myParticles[i];
var q = myParticles[(i+1)%nPoints];
var aSpring = new Spring();
aSpring.set (p, q, K);
mySprings.push(aSpring);
}
var connections = [2,3,5,7,11]; // ha ha tricky, sorry
for (var j=1; j<connections.length; j++) {
for (var i=0; i<nPoints; i++) {
var p = myParticles[i];
var q = myParticles[(i+ connections[j])%nPoints];
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.
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 (0);
var gravityForceX = 0;
var gravityForceY = 0.1;
for (var i=0; i<myParticles.length; i++) {
myParticles[i].update(); // update all locations
}
if (mouseIsPressed && (whichParticleIsGrabbed > -1)) {
// 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].bPeriodicBoundaries = false;
myParticles[i].bHardBoundaries = true;
myParticles[i].addForce(gravityForceX, gravityForceY);
}
for (var i=0; i<mySprings.length; i++) {
mySprings[i].update(); // draw all springs
}
for (var i=0; i<mySprings.length; i++) {
mySprings[i].render(); // draw all springs
}
for (var i=0; i<myParticles.length; i++) {
myParticles[i].render(); // draw all particles
}
noFill();
stroke(0);
rect(0,0,width-1, height-1);
}
//==========================================================
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) {
this.px = x;
this.py = y;
this.vx = 0;
this.vy = 0;
this.damping = 0.96;
this.mass = 1.0;
};
// 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);
}
}
};
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() {
stroke(255);
line(p.px, p.py, q.px, q.py);
};
}