xxxxxxxxxx
243
const POINT_SIZE = 15;
const STICK_WEIGHT = 3;
const STICK_ITERS = 5;
const POINT_COLOR = "#ffffff";
const STICK_COLOR = "#dbdbdb";
let GRAVITY; // Initialized in setup (p5.Vector)
let running = false;
let drawingStick = false;
let drawingStickPoint;
let wind; // Initialized in setup (p5.Vector)
let wind_on = false;
let lastDraggedPos;
class Point {
constructor(x, y) {
this.pos = createVector(x, y);
this.prevPos = this.pos;
this.locked = false;
}
draw() {
push();
this.locked ? fill("#FF0000") : fill("#FFFFFF");
circle(this.pos.x, this.pos.y, POINT_SIZE);
pop();
}
run() {
if (!this.locked) {
let pBefore = this.pos.copy();
this.pos.add(p5.Vector.sub(this.pos, this.prevPos));
this.pos.add(GRAVITY);
if (wind_on) this.pos.add(wind);
this.prevPos = pBefore;
}
}
}
class Stick {
pointDist(p1, p2) { return Math.sqrt(Math.pow(p2.pos.x - p1.pos.x, 2) + Math.pow(p2.pos.y - p1.pos.y, 2)); }
constructor(p1, p2) {
this.p1 = p1;
this.p2 = p2;
this.len = this.pointDist(p1, p2);
}
draw() {
push();
stroke("#dbdbdb");
strokeWeight(STICK_WEIGHT);
line(this.p1.pos.x, this.p1.pos.y,
this.p2.pos.x, this.p2.pos.y);
pop();
}
run() {
if (this.len <= 0) return;
let center = p5.Vector.add(this.p1.pos, this.p2.pos);
center.div(2);
let dir = p5.Vector.sub(this.p1.pos, this.p2.pos);
dir.normalize();
if (!this.p1.locked) {
let p1pos = dir.copy();
p1pos.mult(this.len);
p1pos.div(2);
p1pos.add(center);
this.p1.pos = p1pos;
}
if (!this.p2.locked) {
let p2pos = dir.copy();
p2pos.mult(this.len);
p2pos.div(2);
p2pos = p5.Vector.sub(center, p2pos);
this.p2.pos = p2pos;
}
}
}
let points = [];
let sticks = [];
function setup() {
const canvas = createCanvas(windowWidth, windowHeight);
canvas.elt.addEventListener("contextmenu", (e) => e.preventDefault())
GRAVITY = createVector(0, 0.5);
wind = createVector(0.25, 0);
}
function drawStickInProgress() {
push();
stroke(STICK_COLOR);
strokeWeight(STICK_WEIGHT);
line(drawingStickPoint.pos.x, drawingStickPoint.pos.y, mouseX, mouseY);
pop();
}
function drawMouseCursor() {
push();
noStroke();
fill("#ff0000");
circle(mouseX, mouseY, 5);
pop();
}
function cullPoints() {
// Kill any off-screen points, as well as any attached sticks
for (let i = 0; i < points.length; i++) {
if (points[i].pos.y > windowHeight + (windowHeight * 0.5)) {
for (let j = 0; j < sticks.length; j++) {
if (sticks[j].p1 === points[i] ||
sticks[j].p2 === points[i])
sticks.splice(j, 1);
}
points.splice(i, 1);
}
}
}
function draw() {
background("#0496ba");
points.forEach(p => p.draw());
sticks.forEach(s => s.draw());
if (running) {
points.forEach(p => p.run());
for (let i = 0; i < STICK_ITERS; i++)
sticks.forEach(s => s.run());
}
cullPoints();
if (drawingStick) drawStickInProgress();
if (running && mouseIsPressed) drawMouseCursor();
text(`Points: ${points.length}`, 5, 15);
text(`Sticks: ${sticks.length}`, 5, 30);
text(`Running: ${running}`, 5, 45);
text(`Wind: ${wind_on ? (Math.abs(wind.x).toFixed(2).toString() + (wind.x > 0 ? " East" : " West")) : "off"}`, 5, 60);
}
function mousePressedPoint(p) {
if (mouseButton == LEFT) {
if (drawingStick) {
if (drawingStickPoint === p) {
drawingStick = false;
return;
}
let s = new Stick(drawingStickPoint, p);
sticks.push(s);
drawingStick = false;
} else {
p.locked = !p.locked;
}
} else if (mouseButton == RIGHT) {
if (drawingStick) {
if (drawingStickPoint === p) {
drawingStick = false;
return;
}
let s = new Stick(drawingStickPoint, p);
sticks.push(s);
drawingStick = false;
} else {
drawingStick = true;
drawingStickPoint = p;
}
}
}
function mousePressed() {
if (running) {
} else {
// Check if clicking a point, then pass to mousePressedPoint
for (let i = 0; i < points.length; i++) {
let p = points[i];
if (mouseX < p.pos.x + (POINT_SIZE / 2) &&
mouseX > p.pos.x - (POINT_SIZE / 2) &&
mouseY < p.pos.y + (POINT_SIZE / 2) &&
mouseY > p.pos.y - (POINT_SIZE / 2)) {
mousePressedPoint(p);
return;
}
}
// If clicking into space while creating stick, stop creating stick and return
if (drawingStick) {
drawingStick = false;
return;
}
// If clicking into space, create new point
let p = new Point(mouseX, mouseY);
points.push(p);
}
}
function mouseDragged() {
if (running) {
// If simulation running, allow cutting through sticks
if (lastDraggedPos == null) {
lastDraggedPos = createVector(mouseX, mouseY)
}
}
}
function keyPressed() {
if (keyCode == 32) {
// SPACE
running = !running;
} else if (keyCode == 82) { // R
points = [];
sticks = [];
} else if (keyCode == 87) { // W
wind_on = !wind_on;
} else if (keyCode == 81) { // Q
wind.x -= 0.05;
if (wind.x < -0.5) wind.x = -0.5;
} else if (keyCode == 69) { // E
wind.x += 0.05;
if (wind.x > 0.5) wind.x = 0.5;
} else if (keyCode == 67) { // C
if (running) return;
// Clear points/sticks and create cloth
points = [];
sticks = [];
// Create points
let size_x = 8, size_y = 8;
for (let i = 0; i < size_x; i++) {
for (let j = 0; j < size_y; j++) {
let x = (i * (windowWidth * 0.7 / size_x)) + (windowWidth * 0.2);
let y = (j * (windowHeight * 0.7 / size_y)) + (windowHeight * 0.2);
let p = new Point(x, y);
points.push(p);
// Draw stick up
if (j > 0) {
let s = new Stick(p, points[(j - 1) + i * size_y]);
sticks.push(s);
}
// Draw stick left
if (i > 0) {
let s = new Stick(p, points[j + (i - 1) * size_y]);
sticks.push(s);
}
// Lock top corners
if (j == 0 && (i == 0 || i == size_x - 1)) {
p.locked = true;
}
}
}
}
}