// matter.js cdn: https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.20.0/matter.min.js
const { Engine, Runner, Bodies, Composite } = Matter;
const engine = Engine.create();
const runner = Runner.create();
// particle vars
const particleGraphics = [];
const particleBodies = [];
const numberOfParticles = 100;
// boundaries
let leftwall, rightwall, floor, ceiling;
const namespace = "http://www.w3.org/2000/svg";
const svg = document.querySelector("svg");
const w = parseInt(svg.getAttribute("viewBox").split(" ")[2]);
const h = parseInt(svg.getAttribute("viewBox").split(" ")[3]);
const r = 20;
const wallThickness = 100;
// wind force
let windForce = { x: 0, y: 0 };
const holder = document.querySelector("#holder");
// ui
const replayButton = document.querySelector("#replayButton");
const windSlider = document.querySelector("#windSlider");
const windText = document.querySelector("#forceText");
const initParticle = () => {
for (let i = 0; i < numberOfParticles; i++) {
const color = `hsl(${Math.random()*360} 60% 50%)`;
const particleGraphic = document.createElementNS(namespace, "circle");
particleGraphic.setAttribute("cx", "500");
particleGraphic.setAttribute("cy", "50");
particleGraphic.setAttribute("r", r);
particleGraphic.setAttribute("fill", color);
holder.appendChild(particleGraphic);
particleGraphics.push(particleGraphic);
}
};
const initParticleBody = () => {
for (let i = 0; i < numberOfParticles; i++) {
const xpos = r + Math.random() * (w - 2 * r);
const ypos = r + Math.random() * 50;
const particleBody = Bodies.circle(0, 0, r, {
id: `particleBody_${i}`,
friction: 0,
frictionAir: 0,
restitution: 0.8
});
Matter.Body.setPosition(particleBody, { x: xpos, y: ypos });
particleBodies.push(particleBody);
}
};
const initWallAndFloor = () => {
floor = Bodies.rectangle(w / 2, h + wallThickness / 2, w, wallThickness, {
isStatic: true,
restitution: 1,
id: "floor"
});
ceiling = Bodies.rectangle(w / 2, -wallThickness / 2, w, wallThickness, {
isStatic: true,
restitution: 1,
id: "ceiling"
});
leftwall = Bodies.rectangle(-wallThickness / 2, h / 2, wallThickness, h, {
isStatic: true,
restitution: 1,
id: "leftwall"
});
rightwall = Bodies.rectangle(w + wallThickness / 2, h / 2, wallThickness, h, {
isStatic: true,
restitution: 1,
id: "righttwall"
});
};
const makeWorld = () => {
Composite.add(engine.world, [
...particleBodies,
leftwall,
rightwall,
floor,
ceiling
]);
};
const initRunner = () => {
Runner.run(runner, engine);
};
const initUI = () => {
replayButton.addEventListener("click", () => {
particleBodies.forEach((particleBody) => {
const xpos = r + Math.random() * (w - 2 * r);
const ypos = r + Math.random() * 50;
Matter.Body.setPosition(particleBody, { x: xpos, y: ypos });
Matter.Body.setSpeed(particleBody, 0);
});
});
windSlider.addEventListener("input", (e) => {
console.log(e.target.value);
const force = parseFloat(e.target.value);
windForce.x = force;
windText.textContent = `force: ${force}`;
});
};
const update = () => {
// look at the particleBody position and update graphic position accordingly.
particleBodies.forEach((particleBody, index) => {
const pos = particleBody.position;
Matter.Body.applyForce(particleBody, pos, windForce);
const particleGraphic = particleGraphics[index];
particleGraphic.setAttribute("cx", pos.x);
particleGraphic.setAttribute("cy", pos.y);
});
window.requestAnimationFrame(update);
};
initParticle();
initParticleBody();
initWallAndFloor();
makeWorld();
initRunner();
initUI();
update();