xxxxxxxxxx
208
let objects = [];
let sticks = [];
const sim_steps = 8;
var gravity = null;
const friction = 0.999;
let mouseMode = "add_objects";
let paused = false;
const addStickState = {
o: null,
};
const moveState = {
o: null,
}
function setup() {
createCanvas(600, 600);
gravity = createVector(0, 0.001);
noStroke();
createButton("Pause/unpause")
.mousePressed(() => {
paused = !paused;
});
createButton("Add objects")
.mousePressed(() => mouseMode = "add_objects");
createButton("Add sticks")
.mousePressed(() => mouseMode = "add_sticks");
createButton("Pin/unpin object")
.mousePressed(() => mouseMode = "pin_object");
createButton("Move object")
.mousePressed(() => mouseMode = "move_object");
createButton("Delete object")
.mousePressed(() => mouseMode = "delete_object");
createButton("Clear all")
.mousePressed(() => mouseMode = "clear");
}
function draw() {
background(32);
stroke(0);
fill(192);
circle(width / 2, height / 2, width);
if (!paused) {
const dt = 25 / sim_steps;
for (i = 0; i < sim_steps; i++) {
applyGravity(objects);
updatePositions(objects, dt);
applyConstraints(objects);
handleCollisions(objects);
updateSticks(sticks, dt);
}
}
drawSticks(sticks);
drawObjects(objects);
if (addStickState.o) {
fill("white");
stroke("orange");
strokeWeight(2);
circle(addStickState.o.pos.x, addStickState.o.pos.y, addStickState.o.radius * 2);
strokeWeight(1);
}
if (moveState.o) {
fill("white");
stroke("magenta");
strokeWeight(2);
circle(moveState.o.pos.x, moveState.o.pos.y, moveState.o.radius * 2);
strokeWeight(1);
}
let strMode = "";
switch (mouseMode) {
case "add_objects":
strMode = "Click to add new objects";
break;
case "add_sticks":
strMode = "Click an object, then another to add a stick between them";
break;
case "pin_object":
strMode = "Click an object to pin/unpin it";
break;
case "move_object":
strMode = "Click an object to start moving it, click again to stop";
break;
case "delete_object":
strMode = "Click an object to delete it";
break;
}
noStroke();
fill(192, 192, 64);
text(`${objects.length} objects, ${sticks.length} sticks`, 5, 15);
fill(64, 192, 64);
text(strMode, 5, 30);
if (paused) {
fill(192, 64, 64);
text("--- PAUSED ---", 5, 45);
}
}
function mouseInCanvas() {
return mouseX >= 0 && mouseX <= width && mouseY >= 0 && mouseY <= height;
}
function mouseClicked() {
switch (mouseMode) {
case "add_objects":
if (mouseInCanvas()) {
objects.push(
new VerletObject(
createVector(mouseX, mouseY),
10,
random(["red", "green", "blue", "cyan", "magenta", "yellow", "pink", "purple", "orange"]),
false
)
);
}
break;
case "add_sticks":
if (mouseInCanvas()) {
const o = objectFromPoint(mouseX, mouseY);
if (addStickState.o && o) {
sticks.push(
new Stick(
addStickState.o,
o,
p5.Vector.sub(o.pos, addStickState.o.pos).mag()
)
);
addStickState.o = null;
} else {
addStickState.o = o;
}
}
break;
case "pin_object":
if (mouseInCanvas()) {
const o = objectFromPoint(mouseX, mouseY);
if (o) {
o.pinned = !o.pinned;
if (!o.pinned) {
o.prev_pos.x = o.pos.x;
o.prev_pos.y = o.pos.y;
o.accel.x = 0;
o.accel.y = 0;
}
}
}
break;
case "move_object":
if (mouseInCanvas()) {
if (moveState.o) {
moveState.o = null;
} else {
const o = objectFromPoint(mouseX, mouseY);
if (o) {
moveState.o = o;
}
}
}
break;
case "delete_object":
if (mouseInCanvas()) {
const o = objectFromPoint(mouseX, mouseY);
if (o) {
objects = objects.filter((object) =>
object !== o
);
sticks = sticks.filter((stick) =>
stick.o1 !== o && stick.o2 !== o
);
}
}
break;
case "clear":
if (confirm("Are you sure you want to delete all objects?")) {
objects = [];
sticks = [];
}
}
}
function mouseMoved() {
if (moveState.o) {
moveState.o.pos.x = mouseX;
moveState.o.pos.y = mouseY;
moveState.o.prev_pos.x = mouseX;
moveState.o.prev_pos.y = mouseY;
}
}
function objectFromPoint(x, y) {
for (let idx in objects) {
const o = objects[idx];
if (
x >= o.pos.x - o.radius
&& x <= o.pos.x + o.radius
&& y >= o.pos.y - o.radius
&& y <= o.pos.y + o.radius
) {
return o;
}
}
return null;
}