Skip to content

Instantly share code, notes, and snippets.

@GoSubRoutine
Last active June 8, 2020 16:54
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save GoSubRoutine/f4e383cfc4de8b063df3ee1c3fc66419 to your computer and use it in GitHub Desktop.
Toxic VerletParticle2D
height: 600
<!DOCTYPE html>
<meta charset=utf-8>
<meta name=viewport content=width=device-width,initial-scale=1>
<script async src=https://CDN.JSDelivr.net/npm/p5></script>
<script defer
src=https://CDN.JSDelivr.net/gh/hapticdata/toxiclibsjs/build/toxiclibs.min.js>
</script>
<script defer src=Particle.js></script>
<script defer src=Spring.js></script>
<script defer src=sketch.js></script>
"use strict";
class Particle extends toxi.physics2d.VerletParticle2D {
static get FILL() {
delete this.FILL;
return this.prototype.FILL = this.FILL = color(0o350);
}
static get STROKE() {
delete this.STROKE;
return this.prototype.STROKE = this.STROKE = color('red');
}
display() {
ellipse(this.x, this.y, this.W, this.H);
return this;
}
}
Particle.prototype.H = Particle.H = 10;
Particle.prototype.W = Particle.W = 10;
Particle.prototype.BOLD = Particle.BOLD = 1;
Particle.prototype.FILL = 0o350;
Particle.prototype.STROKE = 'red';
/**
* Toxic VerletParticle2D (v3.2)
* GoToLoop (2018-Feb-16)
*
* Forum.Processing.org/two/discussion/26346/
* class-inheritance-with-toxiclibs-pyhton#Item_22
*
* GitHub.com/CodingTrain/website/tree/master/CodingChallenges/CC_020_ClothSimulation
*
* Bl.ocks.org/GoSubRoutine/f4e383cfc4de8b063df3ee1c3fc66419
*/
"use strict";
const { VerletPhysics2D } = toxi.physics2d,
{ GravityBehavior } = toxi.physics2d.behaviors,
{ Vec2D } = toxi.geom;
const ROWS = 40, COLS = 40,
LAST_ROW = ROWS - 1, LAST_COL = COLS - 1,
GRAV = new GravityBehavior(new Vec2D(0, 1));
const { W, H } = Particle, OFFSET = 6, FORCE = .8,
OFFW = W*OFFSET + (W>>1), OFFH = H + (H>>1),
GAPW = (W>>2) + W, GAPH = (H>>2) + H,
LENGTH = GAPW, WEIGHT = 1, ITERS = 30;
const RENDERER = 'p2d', FPS = 60, BG = 0o100;
let showParticles = false, showSprings = true, cloth, bg;
function setup() {
createCanvas(600, 600, RENDERER).mousePressed(clothDisplayMode);
frameRate(FPS).noSmooth();
ellipseMode(CENTER).colorMode(RGB);
fill(Particle.FILL).strokeCap(ROUND);
bg = color(BG);
insertSpringsToParticles( cloth = createClothParticles() );
lockCornerParticles(cloth);
cloth.addBehavior(GRAV);
cloth.numIterations = ITERS;
}
function draw() {
background(bg);
cloth.update();
showParticles && displayParticles(cloth);
showSprings && displaySprings(cloth);
displayTitle();
}
function clothDisplayMode(evt) {
/*
_onmousedown(evt); // workaround for mouseButton, mouseX & mouseY!
evt.preventDefault();
evt.stopPropagation();
*/
switch (mouseButton) {
case LEFT: return showParticles = !showParticles;
case RIGHT: return showSprings = !showSprings;
default: resetParticles(cloth);
}
}
function displayTitle() {
return top.document.title = round(frameRate());
}
function displayParticles({ particles }) {
strokeWeight(Particle.BOLD).stroke(Particle.STROKE);
for (const p of particles) p.display();
}
function displaySprings({ springs }) {
strokeWeight(Spring.BOLD).stroke(Spring.STROKE);
for (const s of springs) s.display();
}
function lockCornerParticles({ particles }) {
particles[0].lock(); // UP-LEFT
particles[LAST_COL].lock(); // UP-RIGHT
particles[particles.length - ROWS].lock(); // DOWN-LEFT
particles[particles.length - 1].lock(); // DOWN-RIGHT
}
function createClothParticles(phy = new VerletPhysics2D) {
phy.clear();
for (let r = 0; r < ROWS; ++r) {
const y = r*GAPH + OFFH;
for (let c = 0; c < COLS; ++c) {
const x = c*GAPW + OFFW;
phy.addParticle(new Particle(x, y, WEIGHT));
}
}
return phy;
}
function insertSpringsToParticles(phy) {
phy.springs.length = 0;
const { particles } = phy;
for (let r = 0; r < ROWS; ++r) {
const row = r*COLS;
for (let c = 0; c < COLS; ++c) {
const idx = row + c, a = particles[idx];
if (c !== LAST_COL) {
const b = particles[idx + 1];
phy.addSpring(new Spring(a, b, LENGTH, FORCE));
}
if (r !== LAST_ROW) {
const b = particles[idx + COLS];
phy.addSpring(new Spring(a, b, LENGTH, FORCE));
}
}
}
}
function resetParticles({ particles }) {
for (let r = 0; r < ROWS; ++r) {
const row = r*COLS, y = r*GAPH + OFFH;
for (let c = 0; c < COLS; ++c) {
const idx = row + c, x = c*GAPW + OFFW;
particles[idx].set(x, y);
}
}
}
"use strict";
class Spring extends toxi.physics2d.VerletSpring2D {
static get STROKE() {
delete this.STROKE;
return this.prototype.STROKE = this.STROKE = color(0xff);
}
display() {
line(this.a.x, this.a.y, this.b.x, this.b.y);
return this;
}
}
Spring.prototype.BOLD = Spring.BOLD = 2;
Spring.prototype.STROKE = 0xff;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment