codex秒生成的小游戏--贪吃蛇

发布时间:2026/6/28 1:28:16
codex秒生成的小游戏--贪吃蛇 !DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title贪吃蛇/title style *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } body { background: #111; display: flex; justify-content: center; align-items: center; min-height: 100vh; font-family: Segoe UI, system-ui, sans-serif; color: #e0e0e0; } .game-wrapper { background: #1a1a2e; border-radius: 16px; padding: 24px; box-shadow: 0 8px 40px rgba(0,0,0,0.6); } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; padding: 0 4px; } .score-box { font-size: 18px; font-weight: 600; letter-spacing: 0.3px; } .score-box span { color: #f0c040; } .controls { display: flex; gap: 8px; } .controls button { background: #2d2d4e; border: none; color: #ccc; font-size: 14px; padding: 6px 18px; border-radius: 6px; cursor: pointer; transition: background 0.15s; font-family: inherit; } .controls button:hover { background: #3d3d5e; } .controls button:active { background: #4d4d6e; } canvas { display: block; background: #0f0f23; border-radius: 10px; width: 480px; height: 480px; image-rendering: pixelated; } .footer { margin-top: 12px; text-align: center; font-size: 13px; color: #666; } .footer kbd { background: #2a2a3e; padding: 2px 8px; border-radius: 4px; font-family: inherit; font-size: 12px; color: #aaa; } media (max-width: 540px) { .game-wrapper { padding: 16px; border-radius: 12px; } canvas { width: calc(100vw - 64px); height: calc(100vw - 64px); } } /style /head body div classgame-wrapper div classheader div classscore-box span idscore0/span/div div classcontrols button idrestartBtn重新开始/button /div /div canvas idgameCanvas width480 height480/canvas div classfooterkbd↑/kbd kbd↓/kbd kbd←/kbd kbd→/kbd 或 kbdW/kbdkbdA/kbdkbdS/kbdkbdD/kbd 控制方向/div /div script (function(){ const canvas document.getElementById(gameCanvas); const ctx canvas.getContext(2d); const scoreEl document.getElementById(score); const GRID_SIZE 20; // 20×20 网格 const CELL_SIZE 24; // 480/20 const TICK_MS 140; let snake, direction, nextDirection, food, score, gameOver, win; let timer null; // ---- 初始化 / 重置 ---- function init() { snake [ { x: 10, y: 10 }, { x: 9, y: 10 }, { x: 8, y: 10 }, ]; direction { x: 1, y: 0 }; nextDirection { x: 1, y: 0 }; score 0; gameOver false; win false; scoreEl.textContent 0; spawnFood(); draw(); } // ---- 生成食物不与蛇重叠 ---- function spawnFood() { const occupied new Set(snake.map(p ${p.x},${p.y})); const free []; for (let y 0; y GRID_SIZE; y) for (let x 0; x GRID_SIZE; x) if (!occupied.has(${x},${y})) free.push({ x, y }); if (free.length 0) { win true; gameOver true; food null; return; } food free[Math.floor(Math.random() * free.length)]; } // ---- 游戏逻辑 ---- function tick() { if (gameOver) return; direction { ...nextDirection }; const head snake[0]; const nx head.x direction.x; const ny head.y direction.y; // 撞墙 if (nx 0 || nx GRID_SIZE || ny 0 || ny GRID_SIZE) { gameOver true; draw(); return; } // 撞自身 for (const seg of snake) { if (seg.x nx seg.y ny) { gameOver true; draw(); return; } } // 移动 snake.unshift({ x: nx, y: ny }); const ate (food nx food.x ny food.y); if (ate) { score; scoreEl.textContent score; spawnFood(); } else { snake.pop(); } draw(); } // ---- 绘制 ---- function draw() { ctx.clearRect(0, 0, 480, 480); // 网格线很淡 ctx.strokeStyle rgba(255,255,255,0.03); ctx.lineWidth 0.5; for (let i 0; i GRID_SIZE; i) { const p i * CELL_SIZE; ctx.beginPath(); ctx.moveTo(p, 0); ctx.lineTo(p, 480); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, p); ctx.lineTo(480, p); ctx.stroke(); } // 食物 if (food) { const fx food.x * CELL_SIZE, fy food.y * CELL_SIZE; // 苹果渐变 const grad ctx.createRadialGradient(fx6, fy6, 2, fx12, fy12, 14); grad.addColorStop(0, #f55); grad.addColorStop(1, #c33); ctx.fillStyle grad; ctx.beginPath(); ctx.arc(fx CELL_SIZE/2, fy CELL_SIZE/2, CELL_SIZE/2 - 2, 0, Math.PI*2); ctx.fill(); // 高光 ctx.fillStyle rgba(255,255,255,0.25); ctx.beginPath(); ctx.arc(fx 8, fy 8, 3, 0, Math.PI*2); ctx.fill(); } // 蛇身 for (let i snake.length - 1; i 0; i--) { const seg snake[i]; const sx seg.x * CELL_SIZE, sy seg.y * CELL_SIZE; const pad 1; const radius 4; const t i / Math.max(snake.length - 1, 1); // 头部亮绿 → 尾部暗绿 const r Math.round(30 t * 20); const g Math.round(200 - t * 80); const b Math.round(80 - t * 40); ctx.fillStyle rgb(${r},${g},${b}); // 圆角矩形 const x sx pad, y sy pad; const w CELL_SIZE - pad*2, h CELL_SIZE - pad*2; ctx.beginPath(); ctx.moveTo(x radius, y); ctx.lineTo(x w - radius, y); ctx.quadraticCurveTo(x w, y, x w, y radius); ctx.lineTo(x w, y h - radius); ctx.quadraticCurveTo(x w, y h, x w - radius, y h); ctx.lineTo(x radius, y h); ctx.quadraticCurveTo(x, y h, x, y h - radius); ctx.lineTo(x, y radius); ctx.quadraticCurveTo(x, y, x radius, y); ctx.closePath(); ctx.fill(); } // 蛇眼睛头部 if (snake.length 0 !gameOver) { const head snake[0]; const hx head.x * CELL_SIZE, hy head.y * CELL_SIZE; ctx.fillStyle #fff; let e1x, e1y, e2x, e2y; if (direction.x 1) { e1xhx16; e1yhy6; e2xhx16; e2yhy16; } else if (direction.x -1) { e1xhx6; e1yhy6; e2xhx6; e2yhy16; } else if (direction.y 1) { e1xhx6; e1yhy16; e2xhx16; e2yhy16; } else { e1xhx6; e1yhy6; e2xhx16; e2yhy6; } ctx.beginPath(); ctx.arc(e1x, e1y, 3, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(e2x, e2y, 3, 0, Math.PI*2); ctx.fill(); ctx.fillStyle #111; ctx.beginPath(); ctx.arc(e1x, e1y, 1.5, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(e2x, e2y, 1.5, 0, Math.PI*2); ctx.fill(); } // 游戏结束遮罩 if (gameOver) { ctx.fillStyle rgba(0,0,0,0.55); ctx.fillRect(0, 0, 480, 480); ctx.fillStyle #fff; ctx.font bold 28px system-ui, sans-serif; ctx.textAlign center; ctx.textBaseline middle; const msg win ? 你赢了 : 游戏结束; ctx.fillText(msg, 240, 210); ctx.font 16px system-ui, sans-serif; ctx.fillStyle #aaa; ctx.fillText(点击「重新开始」再来一局, 240, 260); } } // ---- 键盘控制 ---- function handleKey(e) { const key e.key; if ([ArrowUp,ArrowDown,ArrowLeft,ArrowRight,w,W,s,S,a,A,d,D].includes(key)) e.preventDefault(); if (gameOver) return; const opp (d1, d2) (d1.x -d2.x d1.y -d2.y); let nd null; if (key ArrowUp || key w || key W) nd { x: 0, y: -1 }; else if (key ArrowDown || key s || key S) nd { x: 0, y: 1 }; else if (key ArrowLeft || key a || key A) nd { x: -1, y: 0 }; else if (key ArrowRight || key d || key D) nd { x: 1, y: 0 }; if (nd !opp(nd, direction)) nextDirection nd; } // ---- 启动/停止循环 ---- function startLoop() { stopLoop(); timer setInterval(tick, TICK_MS); } function stopLoop() { if (timer) { clearInterval(timer); timer null; } } function restart() { init(); startLoop(); } // ---- 绑定事件 ---- document.addEventListener(keydown, handleKey); document.getElementById(restartBtn).addEventListener(click, restart); // ---- 开始 ---- init(); startLoop(); })(); /script /body /html