SOURCE / PINNED RELEASE
Made of little things.
Impossible Machine
- Release
- 841127ac75f3…
- Author-recorded commit
- 123625b81870…
- License
- LICENSE
- Author’s source reference
- nostr://npub1n8ga89w8h6tvwamxusfyzexw8gjy84yxu9rxgnmk955cxtml4ujswzxydd/wss%3A%2F%2Fgit.napplet.soy%2F/n-47d97da9d80
Archive hash verified: db7c8101167c4b07…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
export type Piece = {
id: number;
kind: 'ramp' | 'bumper';
x: number;
y: number;
angle: number;
};
export type Ball = { x: number; y: number; vx: number; vy: number };
export const radius = 10;
export function endpoints(p: Piece) {
const dx = Math.cos(p.angle) * 70,
dy = Math.sin(p.angle) * 70;
return [p.x - dx, p.y - dy, p.x + dx, p.y + dy];
}
export function step(ball: Ball, pieces: Piece[], dt: number) {
ball.vy += 480 * dt;
ball.x += ball.vx * dt;
ball.y += ball.vy * dt;
for (const p of pieces) {
let qx = p.x,
qy = p.y,
r = 34;
if (p.kind === 'ramp') {
const [ax, ay, bx, by] = endpoints(p);
const t = Math.max(
0,
Math.min(
1,
((ball.x - ax) * (bx - ax) + (ball.y - ay) * (by - ay)) / 19600,
),
);
qx = ax + t * (bx - ax);
qy = ay + t * (by - ay);
r = 16;
}
let dx = ball.x - qx,
dy = ball.y - qy,
d = Math.hypot(dx, dy);
if (d >= r) continue;
if (d < 0.0001) {
dx = 0;
dy = -1;
d = 1;
}
const nx = dx / d,
ny = dy / d;
ball.x = qx + nx * r;
ball.y = qy + ny * r;
const vn = ball.vx * nx + ball.vy * ny;
if (vn < 0) {
const bounce = p.kind === 'bumper' ? 1.65 : 1.08;
ball.vx -= bounce * vn * nx;
ball.vy -= bounce * vn * ny;
if (p.kind === 'bumper') {
ball.vx += nx * 55;
ball.vy += ny * 55;
}
}
}
}
export function caught(ball: Ball, cup: { x: number; y: number }) {
return (
Math.abs(ball.x - cup.x) < 29 &&
ball.y > cup.y - 10 &&
ball.y < cup.y + 22 &&
ball.vy >= 0
);
}
