// matter.js cdn: https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.20.0/matter.min.js
const { Engine, Body, Bodies, Composite, Render} = Matter;
const engine = Engine.create();
// svg variables
const viewportWidth = 400;
const viewportHeight = 400
const w = 400;
const h = 400;
// svg namespace just in case we're creating some graphics
const namespace = "http://www.w3.org/2000/svg";
// particle vars
let particleGraphic, particleBody;
const particleGraphics = [];
const particleBodies = [];
const numberOfParticles = 50;
const particleWidth = 15;
const particleHeight = 15;
const wallThickness = 100;
// boundaries
let leftwall, rightwall, floor;
const particleHolder = document.querySelector("#particleHolder");
// ui
const replayButton = document.querySelector("#replayButton");
function initSVG() {
const svg = document.querySelector("svg");
svg.setAttribute("width", `${viewportWidth}`);
svg.setAttribute("height", `${viewportHeight}`);
svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
const bg = document.querySelector("#bg");
bg.setAttribute("width", w);
bg.setAttribute("height", h);
bg.setAttribute("fill", "#eaeaea")
}
function initRenderer() {
// create renderer
const rendererHolder = document.querySelector("#rendererHolder");
const render = Render.create({
element: rendererHolder,
engine: engine,
options: {
width: w,
height: h,
showAngleIndicator: true
}
});
Render.run(render);
}
function initParticleGraphics() {
for (let i = 0; i < numberOfParticles; i++) {
const graphicHolder = 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());
graphicHolder.appendChild(particleGraphic);
particleHolder.appendChild(graphicHolder);
particleGraphics.push(graphicHolder);
}
};
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}`,
friction: 0,
restitution: 0.9
});
const xpos = w/3 + Math.random() * w/3;;
const ypos = Math.random() * (-i * particleHeight*2);
Body.setPosition(particleBody, { x: xpos, y: ypos });
particleBodies.push(particleBody);
}
};
function initWallAndFloor() {
floor = Bodies.rectangle(w/2, h + wallThickness/2, w, wallThickness, {
isStatic: true,
id: "floor"
});
leftwall = Bodies.rectangle(-wallThickness/2, h/2, wallThickness, h, {
isStatic: true,
id: "leftwall"
});
rightwall = Bodies.rectangle(w + wallThickness/2, h/2, wallThickness, h, {
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 = w/3 + Math.random() * w/3;
const ypos = -index * (particleHeight*2);
Body.setPosition(particleBody, { x: xpos, y: ypos });
Body.setSpeed(particleBody, 0);
});
});
};
function update() {
// update the engine
Engine.update(engine);
// look at the particleBody position and update graphic position accordingly.
particleGraphics.forEach((pg, index) => {
const pos = particleBodies[index].position;
const transformString = `translate(${pos.x} ${pos.y})`
pg.setAttribute("transform", transformString);
});
window.requestAnimationFrame(update);
};
initSVG();
initRenderer();
initParticleGraphics();
initParticleBodies();
initWallAndFloor();
makeWorld();
initUI();
update();