import { useEffect, useRef } from "react"; import styles from "./GuessPane.module.css"; const tileSize = 15; const tiles = 40; const rawSize = tileSize * tiles; const drawTile = (ctx, x, y, color) => { ctx.fillStyle = color; ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize); }; const snakeGame = () => { const snakeHead = { x: null, y: null, vx: null, vy: null }; let snakeTail = []; const apple = { x: null, y: null }; const randomApple = () => { apple.x = Math.floor(Math.random() * tiles); apple.y = Math.floor(Math.random() * tiles); }; const reset = () => { snakeHead.x = Math.floor(tiles / 2); snakeHead.y = snakeHead.x; snakeHead.vx = 0; snakeHead.vy = -1; snakeTail = [{ ...snakeHead }]; randomApple(); }; reset(); const onKey = ({ code }) => { switch (code) { case "ArrowUp": snakeHead.vx = 0; snakeHead.vy = -1; break; case "ArrowDown": snakeHead.vx = 0; snakeHead.vy = 1; break; case "ArrowLeft": snakeHead.vx = -1; snakeHead.vy = 0; break; case "ArrowRight": snakeHead.vx = 1; snakeHead.vy = 0; break; default: break; } }; let interval; const start = (ctx, finishScore, onFinish) => { document.addEventListener("keydown", onKey); interval = setInterval(() => { snakeHead.x += snakeHead.vx; snakeHead.y += snakeHead.vy; if ( snakeHead.x < 0 || snakeHead.x >= tiles || snakeHead.y < 0 || snakeHead.y >= tiles || snakeTail.find(({ x, y }) => x === snakeHead.x && y === snakeHead.y) ) { reset(); } snakeTail.push({ ...snakeHead }); if (apple.x === snakeHead.x && apple.y === snakeHead.y) { randomApple(); } else { snakeTail.shift(); } const finished = snakeTail.length >= finishScore; ctx.fillStyle = "black"; ctx.fillRect(0, 0, rawSize, rawSize); snakeTail.forEach(({ x, y }) => { drawTile(ctx, x, y, "green"); }); if (!finished) { drawTile(ctx, apple.x, apple.y, "red"); } ctx.font = "24px serif"; ctx.fillStyle = "#fff"; ctx.textAlign = "left"; ctx.textBaseline = "top"; ctx.fillText(`${snakeTail.length}/${finishScore}`, tileSize, tileSize); if (finished) { clearInterval(interval); interval = null; ctx.font = "48px serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("Done!", rawSize / 2, rawSize / 2); setTimeout(onFinish, 1000); } }, 50); }; const stop = () => { document.removeEventListener("keydown", onKey); if (interval) { clearInterval(interval); } }; return { start, stop, onKey }; }; const GunGame = ({ points, onFinish }) => { const ref = useRef(); useEffect(() => { const { start, stop } = snakeGame(); start(ref.current?.getContext("2d"), 10, onFinish); return () => { stop(); }; }, [onFinish]); return (