讨论

构建一个完整的打砖块街机游戏,使用HTML

来自 Wikiprompt,自由的提示词百科全书

Eyisha Zyer

2026年7月11日

构建一个完整的打砖块街机游戏,使用HTML 一个全面的提示,用于在单个HTML文件中生成一个功能完整的Breakout游戏,涵盖游戏玩法、控制、视觉效果、音频和技术细节。

提示词内容收藏

🌐
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <title>NEON BREAKOUT</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; user-select: none; } body { background: #0a0f1e; min-height: 100vh; display: flex; align-items: center; justify-content: center; font-family: 'Segoe UI', system-ui, sans-serif; touch-action: none; overflow: hidden; } .game-container { background: #0f172a; border-radius: 2rem; padding: 1.5rem; box-shadow: 0 0 40px rgba(0, 200, 255, 0.3), 0 0 80px rgba(0, 100, 255, 0.2); border: 1px solid #2a3a5e; } canvas { display: block; width: 100%; max-width: 900px; height: auto; border-radius: 1rem; background: #0b1120; box-shadow: inset 0 0 30px #00000066, 0 0 20px #00a6ff40; cursor: none; touch-action: none; } .hud { display: flex; justify-content: space-between; align-items: center; padding: 0.5rem 0.2rem 1rem 0.2rem; color: #b0e0ff; font-weight: 600; letter-spacing: 1px; text-shadow: 0 0 8px #00a6ff; } .hud span { background: #1e293b; padding: 0.4rem 1.2rem; border-radius: 3rem; font-size: 1.1rem; border: 1px solid #3b5a8a; box-shadow: 0 0 10px #00a6ff33; } .hud .level-badge { background: #1e293b; padding: 0.4rem 1.2rem; border-radius: 3rem; font-size: 1.1rem; border: 1px solid #ffaa33; color: #ffd966; text-shadow: 0 0 8px #ffaa33; } .hud .lives { color: #ff6b9d; text-shadow: 0 0 12px #ff4d7d; font-size: 1.4rem; } .hud .score { color: #7df9ff; } .controls-hint { color: #5f7a9f; font-size: 0.8rem; text-align: center; margin-top: 0.8rem; letter-spacing: 1px; border-top: 1px solid #1e2f4a; padding-top: 0.8rem; } .controls-hint kbd { background: #1e293b; padding: 0.1rem 0.6rem; border-radius: 0.5rem; border: 1px solid #3b5a8a; color: #aad0ff; } </style> </head> <body> <div class="game-container"> <div class="hud"> <span class="score">SCORE: 0</span> <span class="level-badge">LEVEL 1</span> <span class="lives">❤️❤️❤️</span> </div> <canvas id="gameCanvas" width="900" height="600"></canvas> <div class="controls-hint"> <kbd>←</kbd> <kbd>→</kbd> / mouse · <kbd>SPACE</kbd> launch · <kbd>P</kbd> pause </div> </div> <script> (function() { const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const scoreEl = document.querySelector('.score'); const levelEl = document.querySelector('.level-badge'); const livesEl = document.querySelector('.lives'); // ---------- GAME STATE ---------- let gameState = 'START'; // START, PLAYING, PAUSED, GAMEOVER, WIN let score = 0; let lives = 3; let level = 1; let ballSpeedMultiplier = 1.0; let particles = []; let powerUpActive = { multiBall: false, widePaddle: false, slowBall: false }; let powerUpTimers = { multiBall: 0, widePaddle: 0, slowBall: 0 }; let frameCount = 0; // paddle const paddle = { x: 450, y: 560, w: 120, h: 14, color: '#00e5ff' }; const defaultPaddleWidth = 120; let mouseX = 450; // ball(s) let balls = []; const ballRadius = 8; const defaultBallSpeed = 5.5; // bricks let bricks = []; const brickRows = 6; const brickCols = 10; const brickWidth = 70; const brickHeight = 22; const brickPadding = 8; const brickOffsetTop = 60; const brickOffsetLeft = 40; // input let keys = { left: false, right: false }; // ---------- AUDIO (synthetic) ---------- function playTone(freq, duration = 0.1, type = 'square', volume = 0.15) { try { const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.type = type; osc.frequency.value = freq; gain.gain.value = volume; osc.connect(gain); gain.connect(audioCtx.destination); osc.start(); setTimeout(() => { osc.stop(); audioCtx.close(); }, duration * 1000); } catch (e) { /* audio not critical */ } } function soundBounce() { playTone(220, 0.08, 'triangle', 0.1); } function soundBrick() { playTone(520, 0.1, 'square', 0.12); } function soundGameOver() { playTone(120, 0.5, 'sawtooth', 0.2); } function soundWin() { playTone(880, 0.3, 'sine', 0.15); setTimeout(() => playTone(1100, 0.3, 'sine', 0.15), 150); } // ---------- BRICK LAYOUT ---------- function createBricks() { bricks = []; const colors = ['#ff4d6d', '#ff9e4d', '#ffd166', '#6bffb8', '#4dc9ff', '#c77dff']; for (let r = 0; r < brickRows; r++) { for (let c = 0; c < brickCols; c++) { const x = brickOffsetLeft + c * (brickWidth + brickPadding); const y = brickOffsetTop + r * (brickHeight + brickPadding); bricks.push({ x, y, w: brickWidth, h: brickHeight, color: colors[r % colors.length], alive: true, glow: 0.6 + Math.random() * 0.4 }); } } } // ---------- BALLS ---------- function createBall(x = paddle.x, y = paddle.y - 20, speed = defaultBallSpeed) { return { x, y, vx: (Math.random() > 0.5 ? 1 : -1) * speed * 0.6, vy: -speed, radius: ballRadius, trail: [] }; } function resetBalls() { balls = [createBall()]; powerUpActive.multiBall = false; powerUpTimers.multiBall = 0; } // ---------- PARTICLES ---------- function spawnBrickParticles(brick) { for (let i = 0; i < 14; i++) { particles.push({ x: brick.x + brick.w / 2, y: brick.y + brick.h / 2, vx: (Math.random() - 0.5) * 8, vy: (Math.random() - 0.5) * 8 - 2, life: 1.0, size: 3 + Math.random() * 5, color: brick.color }); } } function updateParticles() { particles = particles.filter(p => p.life > 0); particles.forEach(p => { p.x += p.vx; p.y += p.vy; p.vy += 0.1; p.life -= 0.02; }); } // ---------- COLLISION & GAME LOGIC ---------- function ballWallCollision(ball) { if (ball.x - ball.radius < 0) { ball.x = ball.radius; ball.vx = -ball.vx; soundBounce(); } if (ball.x + ball.radius > canvas.width) { ball.x = canvas.width - ball.radius; ball.vx = -ball.vx; soundBounce(); } if (ball.y - ball.radius < 0) { ball.y = ball.radius; ball.vy = -ball.vy; soundBounce(); } } function ballPaddleCollision(ball) { if (ball.y + ball.radius >= paddle.y && ball.y + ball.radius <= paddle.y + paddle.h + 8 && ball.x >= paddle.x - ball.radius && ball.x <= paddle.x + paddle.w + ball.radius && ball.vy > 0) { // angle based on hit position const hitPos = (ball.x - paddle.x) / paddle.w; // 0..1 const angle = (hitPos - 0.5) * Math.PI * 0.7; const speed = Math.sqrt(ball.vx * ball.vx + ball.vy * ball.vy); ball.vx = Math.sin(angle) * speed; ball.vy = -Math.abs(Math.cos(angle) * speed); ball.y = paddle.y - ball.radius - 1; soundBounce(); } } function ballBrickCollision(ball) { for (let i = 0; i < bricks.length; i++) { const b = bricks[i]; if (!b.alive) continue; if (ball.x + ball.radius > b.x && ball.x - ball.radius < b.x + b.w && ball.y + ball.radius > b.y && ball.y - ball.radius < b.y + b.h) { b.alive = false; score += 10; updateScore(); spawnBrickParticles(b); soundBrick(); // simple reflection const overlapLeft = (ball.x + ball.radius) - b.x; const overlapRight = (b.x + b.w) - (ball.x - ball.radius); const overlapTop = (ball.y + ball.radius) - b.y; const overlapBottom = (b.y + b.h) - (ball.y - ball.radius); const minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom); if (minOverlap === overlapLeft || minOverlap === overlapRight) { ball.vx = -ball.vx; } else { ball.vy = -ball.vy; } // power-up chance (10%) if (Math.random() < 0.1) { applyRandomPowerUp(); } break; } } } function applyRandomPowerUp() { const r = Math.random(); if (r < 0.33) { // multi-ball if (balls.length < 4) { const newBall = createBall(balls[0].x, balls[0].y, defaultBallSpeed * 0.9); newBall.vx = -balls[0].vx * 0.8; newBall.vy = -balls[0].vy * 0.9; balls.push(newBall); powerUpActive.multiBall = true; powerUpTimers.multiBall = 300; } } else if (r < 0.66) { // wide paddle paddle.w = defaultPaddleWidth * 1.5; powerUpActive.widePaddle = true; powerUpTimers.widePaddle = 400; } else { // slow ball balls.forEach(b => { b.vx *= 0.7; b.vy *= 0.7; }); powerUpActive.slowBall = true; powerUpTimers.slowBall = 300; } } function updatePowerUps() { if (powerUpTimers.widePaddle > 0) { powerUpTimers.widePaddle--; if (powerUpTimers.widePaddle === 0) { paddle.w = defaultPaddleWidth; powerUpActive.widePaddle = false; } } if (powerUpTimers.multiBall > 0) { powerUpTimers.multiBall--; if (powerUpTimers.multiBall === 0) { powerUpActive.multiBall = false; } } if (powerUpTimers.slowBall > 0) { powerUpTimers.slowBall--; if (powerUpTimers.slowBall === 0) { powerUpActive.slowBall = false; } } } // ---------- UI UPDATES ---------- function updateScore() { scoreEl.textContent = `SCORE: ${score}`; } function updateLives() { const hearts = lives > 0 ? '❤️'.repeat(lives) + '🖤'.repeat(Math.max(0, 3 - lives)) : '💔'; livesEl.innerHTML = hearts; } function updateLevel() { levelEl.textContent = `LEVEL ${level}`; } // ---------- GAME STATE ---------- function resetGame() { score = 0; lives = 3; level = 1; ballSpeedMultiplier = 1.0; updateScore(); updateLives(); updateLevel(); createBricks(); resetBalls(); paddle.x = canvas.width / 2 - paddle.w / 2; paddle.w = defaultPaddleWidth; powerUpActive = { multiBall: false, widePaddle: false, slowBall: false }; powerUpTimers = { multiBall: 0, widePaddle: 0, slowBall: 0 }; particles = []; gameState = 'START'; } function checkWin() { if (bricks.every(b => !b.alive)) { gameState = 'WIN'; soundWin(); } } function checkGameOver() { if (lives <= 0) { gameState = 'GAMEOVER'; soundGameOver(); } } // ---------- UPDATE ---------- function update() { if (gameState !== 'PLAYING') return; // paddle movement if (keys.left) paddle.x -= 8; if (keys.right) paddle.x += 8; paddle.x = Math.max(0, Math.min(canvas.width - paddle.w, paddle.x)); // mouse follow if (mouseX > 0 && mouseX < canvas.width) { paddle.x = Math.max(0, Math.min(canvas.width - paddle.w, mouseX - paddle.w / 2)); } // update balls balls.forEach(ball => { ball.x += ball.vx; ball.y += ball.vy; ballWallCollision(ball); ballPaddleCollision(ball); ballBrickCollision(ball); }); // remove balls that fell below const before = balls.length; balls = balls.filter(b => b.y < canvas.height + 30); if (balls.length < before) { // lost a ball if (balls.length === 0) { lives--; updateLives(); if (lives > 0) { resetBalls(); gameState = 'START'; } else { checkGameOver(); } } } updateParticles(); updatePowerUps(); checkWin(); } // ---------- RENDER ---------- function drawBackground() { const grad = ctx.createLinearGradient(0, 0, 0, canvas.height); grad.addColorStop(0, '#0b1120'); grad.addColorStop(1, '#0f1a2f'); ctx.fillStyle = grad; ctx.fillRect(0, 0, canvas.width, canvas.height); // subtle grid ctx.strokeStyle = '#1e2f4a22'; ctx.lineWidth = 0.5; for (let i = 0; i < canvas.width; i += 40) { ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, canvas.height); ctx.stroke(); } for (let i = 0; i < canvas.height; i += 40) { ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(canvas.width, i); ctx.stroke(); } } function drawBricks() { bricks.forEach(b => { if (!b.alive) return; ctx.shadowColor = b.color; ctx.shadowBlur = 15; ctx.fillStyle = b.color; ctx.beginPath(); ctx.roundRect(b.x, b.y, b.w, b.h, 6); ctx.fill(); // inner glow ctx.shadowBlur = 5; ctx.fillStyle = 'rgba(255,255,255,0.2)'; ctx.beginPath(); ctx.roundRect(b.x + 2, b.y + 2, b.w - 4, b.h - 4, 4); ctx.fill(); }); ctx.shadowBlur = 0; } function drawPaddle() { ctx.shadowColor = '#00e5ff'; ctx.shadowBlur = 20; ctx.fillStyle = '#00e5ff'; ctx.beginPath(); ctx.roundRect(paddle.x, paddle.y, paddle.w, paddle.h, 8); ctx.fill(); ctx.shadowBlur = 0; // paddle core ctx.fillStyle = '#aaf0ff'; ctx.beginPath(); ctx.roundRect(paddle.x + 4, paddle.y + 2, paddle.w - 8, paddle.h - 4, 6); ctx.fill(); } function drawBalls() { balls.forEach(b => { ctx.shadowColor = '#ffd966'; ctx.shadowBlur = 20; ctx.fillStyle = '#ffd966'; ctx.beginPath(); ctx.arc(b.x, b.y, b.radius, 0, Math.PI * 2); ctx.fill(); ctx.shadowBlur = 0; ctx.fillStyle = '#fff7d6'; ctx.beginPath(); ctx.arc(b.x - 2, b.y - 2, b.radius * 0.5, 0, Math.PI * 2); ctx.fill(); }); } function drawParticles() { particles.forEach(p => { ctx.globalAlpha = Math.max(0, p.life); ctx.fillStyle = p.color; ctx.shadowColor = p.color; ctx.shadowBlur = 10; ctx.beginPath(); ctx.arc(p.x, p.y, p.size * p.life, 0, Math.PI * 2); ctx.fill(); }); ctx.globalAlpha = 1; ctx.shadowBlur = 0; } function drawOverlays() { ctx.fillStyle = 'rgba(0,0,0,0.6)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#ffffff'; ctx.font = 'bold 36px "Segoe UI", sans-serif'; ctx.textAlign = 'center'; ctx.shadowColor = '#00a6ff'; ctx.shadowBlur = 20; if (gameState === 'START') { ctx.fillText('🚀 PRESS SPACE', canvas.width/2, canvas.height/2 - 20); ctx.font = '20px sans-serif'; ctx.fillText('move: mouse / ← →', canvas.width/2, canvas.height/2 + 30); } else if (gameState === 'PAUSED') { ctx.fillText('⏸ PAUSED', canvas.width/2, canvas.height/2); ctx.font = '20px sans-serif'; ctx.fillText('press P to resume', canvas.width/2, canvas.height/2 + 40); } else if (gameState === 'GAMEOVER') { ctx.fillStyle = '#ff6b6b'; ctx.fillText('GAME OVER', canvas.width/2, canvas.height/2 - 20); ctx.font = '24px sans-serif'; ctx.fillStyle = '#fff'; ctx.fillText(`score: ${score} · press SPACE`, canvas.width/2, canvas.height/2 + 30); } else if (gameState === 'WIN') { ctx.fillStyle = '#ffd966'; ctx.fillText('🏆 YOU WIN!', canvas.width/2, canvas.height/2 - 20); ctx.font = '24px sans-serif'; ctx.fillStyle = '#fff'; ctx.fillText(`score: ${score} · press SPACE`, canvas.width/2, canvas.height/2 + 30); } ctx.shadowBlur = 0; } // roundRect helper CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) { if (w < 2 * r) r = w / 2; if (h < 2 * r) r = h / 2; this.moveTo(x + r, y); this.lineTo(x + w - r, y); this.quadraticCurveTo(x + w, y, x + w, y + r); this.lineTo(x + w, y + h - r); this.quadraticCurveTo(x + w, y + h, x + w - r, y + h); this.lineTo(x + r, y + h); this.quadraticCurveTo(x, y + h, x, y + h - r); this.lineTo(x, y + r); this.quadraticCurveTo(x, y, x + r, y); return this; }; function render() { drawBackground(); drawBricks(); drawPaddle(); drawBalls(); drawParticles(); if (gameState === 'START' || gameState === 'PAUSED' || gameState === 'GAMEOVER' || gameState === 'WIN') { drawOverlays(); } } // ---------- GAME LOOP ---------- function gameLoop() { update(); render(); requestAnimationFrame(gameLoop); } // ---------- EVENT LISTENERS ---------- function handleKeyDown(e) { const key = e.key; if (key === 'ArrowLeft') { keys.left = true; e.preventDefault(); } if (key === 'ArrowRight') { keys.right = true; e.preventDefault(); } if (key === ' ') { e.preventDefault(); if (gameState === 'START') { gameState = 'PLAYING'; // launch ball if needed if (balls.length === 0) resetBalls(); balls.forEach(b => { if (b.vy === 0) b.vy = -defaultBallSpeed; }); } else if (gameState === 'GAMEOVER' || gameState === 'WIN') { resetGame(); gameState = 'START'; } } if (key === 'p' || key === 'P') { if (gameState === 'PLAYING') gameState = 'PAUSED'; else if (gameState === 'PAUSED') gameState = 'PLAYING'; } } function handleKeyUp(e) { if (e.key === 'ArrowLeft') keys.left = false; if (e.key === 'ArrowRight') keys.right = false; } function handleMouseMove(e) { const rect = canvas.getBoundingClientRect(); const scaleX = canvas.width / rect.width; mouseX = (e.clientX - rect.left) * scaleX; } function handleTouchMove(e) { e.preventDefault(); const rect = canvas.getBoundingClientRect(); const touch = e.touches[0]; mouseX = (touch.clientX - rect.left) * (canvas.width / rect.width); } // ---------- INIT ---------- function init() { resetGame(); gameState = 'START'; window.addEventListener('keydown', handleKeyDown); window.addEventListener('keyup', handleKeyUp); canvas.addEventListener('mousemove', handleMouseMove); canvas.addEventListener('touchmove', handleTouchMove, { passive: false }); canvas.addEventListener('touchstart', (e) => e.preventDefault()); gameLoop(); } init(); })(); </script> </body> </html>

登录以查看完整提示词

继续使用:

登录即表示你同意我们的 使用条款 和 隐私政策

用法

此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。

为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。

参考资料

分类:coding| twitter| breakout-game| html5-canvas

讨论