xxxxxxxxxx
247
var myParticles = [];
var mySprings = [];
// The number of particles in the grid of springs, in x and y
var nX = 5;
var nY = 5;
var indexOfParticleToWiggle = 2;
//-------------------------
function setup() {
createCanvas(400, 400);
createParticles();
createSpringMeshConnectingParticles();
}
//-------------------------
function createParticles(){
// Create a bunch of (nX*nY) particles,
// which happen to be positioned on a grid
for (var y = 0; y < nY; y++) {
for (var x = 0; x < nX; x++) {
var rx = 100 + x * 50;
var ry = 100 + y * 50;
var p = new Particle();
p.set(rx, ry);
myParticles.push(p);
}
}
// Set the bottom row of particles to be "fixed".
// They won't be affected by forces.
for (var i=(nX*(nY-1)); i<(nX*nY); i++){
myParticles[i].bFixed = true;
}
}
//-------------------------
function createSpringMeshConnectingParticles(){
// Stitch the particles together into a mesh,
// by (selectively) connecting them with springs.
// The spring constant.
var K = 0.03;
// Make springs between each particle and the one to its right.
for (var y = 0; y < nY; y++) {
for (var x = 0; x < nX - 1; x++) {
var p = myParticles[y * nX + x];
var q = myParticles[y * nX + x + 1];
var aSpring = new Spring();
aSpring.set(p, q, K);
mySprings.push(aSpring);
}
}
// Make springs between each particle and the one below it.
for (var y = 0; y < nY - 1; y++) {
for (var x = 0; x < nX; x++) {
var p = myParticles[y * nX + x];
var q = myParticles[(y + 1) * nX + x];
var aSpring = new Spring();
aSpring.set(p, q, K);
mySprings.push(aSpring);
}
}
// Diagonal springs: connect each particle to the one below right.
for (var y = 0; y < nY - 1; y++) {
for (var x = 0; x < nX - 1; x++) {
var p = myParticles[y * nX + x];
var q = myParticles[(y + 1) * nX + x + 1];
var aSpring = new Spring();
aSpring.set(p, q, K);
mySprings.push(aSpring);
}
}
// Diagonal springs: connect each particle to the one below left.
for (var y = 0; y < nY - 1; y++) {
for (var x = 1; x < nX; x++) {
var p = myParticles[y * nX + x];
var q = myParticles[(y + 1) * nX + x - 1];
var aSpring = new Spring();
aSpring.set(p, q, K);
mySprings.push(aSpring);
}
}
}
//-------------------------
function draw() {
background(0);
for (var i = 0; i < myParticles.length; i++) {
if (i == indexOfParticleToWiggle){
// Take one special particle, move it around
var tx = millis()/1000.0;
var ty = millis()/400.0;
var xWiggle = 80*(noise(tx)-0.5);
var yWiggle = 50*sin(ty);
myParticles[i].px = 200 + xWiggle;
myParticles[i].py = 100 + yWiggle;
} else {
// Update all other particles.
myParticles[i].update(); // update all locations
}
}
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
}
for (var i=0; i<myParticles.length; i++) {
myParticles[i].render(); // Draw all particles
}
}
//==========================================================
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);
};
}