// matter.js cdn: https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.20.0/matter.min.js
const { Engine, Runner, Bodies, Composite, World } = Matter;
const engine = Engine.create();
// particle vars
const particleGraphics = [];
const particleBodies = [];
const numberOfParticles = 100;
const particleWidth = 40;
const particleHeight = 40;
// boundaries
let leftwall, rightwall, floor;
const namespace = "http://www.w3.org/2000/svg";
const w = 1000;
const h = 1000;
// particle holder
const holder = document.querySelector("#holder");
// ui
const replayButton = document.querySelector("#replayButton");
function initParticleGraphics() {
// in order to properly rotate the square particles from their center point, the way MatterJS does, we need to center the rectangle in a group. Then we can apply the translation and rotation on the group.
for (let i = 0; i < numberOfParticles; i++) {
const particleGraphicHolder = document.createElementNS(namespace, "g");
const particleGraphic = document.createElementNS(namespace, "rect");
particleGraphic.setAttribute("x", -particleWidth / 2);
particleGraphic.setAttribute("y", -particleHeight / 2);
particleGraphic.setAttribute("width", particleWidth);
particleGraphic.setAttribute("height", particleHeight);
particleGraphic.setAttribute("fill", getRandomColor());
particleGraphic.setAttribute("stroke", "none");
particleGraphicHolder.appendChild(particleGraphic);
holder.appendChild(particleGraphicHolder);
particleGraphics.push(particleGraphicHolder);
}
};
function getRandomColor() {
return `hsl(${Math.round(Math.random() * 360)} 50% 50%)`;
};
function initParticleBodies() {
for (let i = 0; i < numberOfParticles; i++) {
const particleBody = Bodies.rectangle(0, 0, particleWidth, particleHeight, {
id: `particleBody_${i}`,
isStatic: false,
ifriction: 0,
restitution: 0.6
});
const xpos = 200 + Math.random() * (w - 400);
const ypos = -i * 30;
Matter.Body.setPosition(particleBody, { x: xpos, y: ypos });
//Matter.Body.rotate(particleBody, Math.random() * 2 * Math.PI);
//Matter.Body.setAngularSpeed(particleBody, 0.1);
particleBodies.push(particleBody);
}
};
function initWallAndFloor() {
floor = Bodies.rectangle(500, 1050, 1000, 100, {
isStatic: true,
id: "floor"
});
leftwall = Bodies.rectangle(-50, 500, 100, 1000, {
isStatic: true,
id: "leftwall"
});
rightwall = Bodies.rectangle(1050, 500, 100, 1000, {
isStatic: true,
id: "righttwall"
});
};
function makeWorld() {
Composite.add(engine.world, [...particleBodies, leftwall, rightwall, floor]);
};
function initUI() {
replayButton.addEventListener("click", () => {
particleBodies.forEach((particleBody, index) => {
const xpos = 200 + Math.random() * (w - 400);
const ypos = -index * 30;
Matter.Body.setPosition(particleBody, { x: xpos, y: ypos });
Matter.Body.setSpeed(particleBody, 0);
// Matter.Body.rotate(particleBody, 0.1);
// Matter.Body.setAngularSpeed(particleBody, 0.1);
});
});
};
function update() {
Engine.update(engine);
// look at the particleBody position and update graphic position accordingly.
particleGraphics.forEach((pg, index) => {
const pos = particleBodies[index].position;
const angle = particleBodies[index].angle;
const degrees = (angle * 180) / Math.PI;
pg.setAttribute(
"transform",
`translate(${pos.x} ${pos.y}) rotate(${degrees})`
);
});
window.requestAnimationFrame(update);
};
initParticleGraphics();
initParticleBodies();
initWallAndFloor();
makeWorld();
initUI();
update();