Skip to content

Instantly share code, notes, and snippets.

@xl1
Last active October 10, 2023 05:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xl1/4ccd163c82da48f9ec87a98acf905a4b to your computer and use it in GitHub Desktop.
Save xl1/4ccd163c82da48f9ec87a98acf905a4b to your computer and use it in GitHub Desktop.
suika
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>suika</title>
<meta name="viewport" content="width=800">
<script type="module" src="index.js"></script>
</head>
<body style="margin:0;"></body>
</html>
import Matter from 'https://esm.sh/matter-js@0.19.0';
const {
Engine,
Render,
Runner,
Bodies,
Composite,
Events,
Mouse,
MouseConstraint,
} = Matter;
const size = index => 12 + 12 * index;
const styles = {
wall: { fillStyle: '#444' },
balls: [
{ fillStyle: 'hsl( 0, 100%, 40%)' },
{ fillStyle: 'hsl( 72, 100%, 40%)' },
{ fillStyle: 'hsl(144, 100%, 40%)' },
{ fillStyle: 'hsl(216, 100%, 40%)' },
{ fillStyle: 'hsl(288, 100%, 40%)' },
{ fillStyle: 'hsl( 36, 100%, 40%)' },
{ fillStyle: 'hsl(108, 100%, 40%)' },
{ fillStyle: 'hsl(180, 100%, 40%)' },
{ fillStyle: 'hsl(252, 100%, 40%)' },
{ fillStyle: 'hsl(324, 100%, 40%)' },
{ fillStyle: 'hsl(140, 100%, 20%)' },
]
};
let next;
const getNext = () => {
const index = Math.random() * 5 | 0;
return next = {
index,
size: size(index),
render: styles.balls[index]
};
};
getNext();
// engine
const engine = Engine.create();
const render = Render.create({
element: document.body,
engine,
options: {
width: 800,
height: 600,
wireframes: false,
}
});
Composite.add(engine.world, [
Bodies.rectangle(300, 610, 620, 120, { isStatic: true, render: styles.wall }),
Bodies.rectangle(20, 300, 60, 500, { isStatic: true, render: styles.wall }),
Bodies.rectangle(580, 300, 60, 500, { isStatic: true, render: styles.wall }),
]);
// mouse
const mouse = Mouse.create(render.canvas);
const mouseConstraint = MouseConstraint.create(engine, { mouse });
Composite.add(engine.world, mouseConstraint);
render.mouse = mouse;
function addBall(x, y, index) {
const render = styles.balls[index];
const ball = Bodies.circle(x, y, size(index), { render, label: index.toString() });
Composite.add(engine.world, [ball]);
}
Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);
// events
Events.on(mouseConstraint, 'mousedown', event => {
addBall(event.mouse.position.x, 50, next.index);
getNext();
});
Events.on(render, 'afterRender', () => {
const { context } = render;
context.fillStyle = 'white';
context.font = '20px sans-serif';
context.fillText('NEXT', 680, 200);
context.fillStyle = next.render.fillStyle;
context.beginPath();
context.arc(710, 300, Math.min(50, next.size), 0, Math.PI * 2, true);
context.fill();
});
Events.on(engine, 'collisionStart', event => {
for (const { bodyA, bodyB } of event.pairs) {
if (bodyA.label !== 'Body' && bodyA.label === bodyB.label) {
const index = parseInt(bodyA.label, 10);
if (!isNaN(index) && index < styles.balls.length - 1) {
const x = (bodyA.position.x + bodyB.position.x) / 2;
const y = (bodyA.position.y + bodyB.position.y) / 2;
Composite.remove(engine.world, [bodyA, bodyB]);
addBall(x, y, index + 1);
return;
}
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment