Baue ein vollständiges Breakout-Arcade-Spiel in HTML
Von Wikiprompt, der freien Prompt-Enzyklopädie
Baue ein vollständiges Breakout-Arcade-Spiel in HTML Ein umfassender Prompt zur Erstellung eines voll funktionsfähigen Breakout-Spiels in einer einzigen HTML-Datei, der Gameplay, Steuerung, visuelle Effekte, Audio und technische Details abdeckt.
Prompt-InhaltSpeichern
🌐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NEON BREAKOUT</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
body {
background: #0a0f1e;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', system-ui, sans-serif;
touch-action: none;
}
.game-wrapper {
background: #111827;
border-radius: 24px;
padding: 16px;
box-shadow: 0 0 40px rgba(0, 255, 255, 0.15), 0 20px 40px rgba(0,0,0,0.8);
border: 1px solid #2a3a5e;
}
canvas {
display: block;
width: 100%;
max-width: 900px;
height: auto;
border-radius: 16px;
background: #0b1322;
box-shadow: inset 0 0 30px rgba(0,0,0,0.6), 0 0 20px rgba(0, 200, 255, 0.2);
cursor: none;
}
.info-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 8px 4px 8px;
color: #b3e0ff;
font-weight: 600;
letter-spacing: 1px;
text-shadow: 0 0 8px #00ccff;
}
.info-item {
display: flex;
gap: 12px;
background: #1e293b;
padding: 6px 16px;
border-radius: 40px;
border: 1px solid #3b4b6b;
box-shadow: 0 0 12px rgba(0,255,255,0.2);
}
.badge {
background: #0f172a;
padding: 4px 12px;
border-radius: 30px;
color: #7dd3fc;
border: 1px solid #2c3e5e;
}
.btn-reset {
background: #1e293b;
border: 1px solid #4a6a9a;
color: #a0d8ff;
padding: 6px 18px;
border-radius: 40px;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 0 10px #00aaff33;
}
.btn-reset:hover {
background: #2d3f5e;
box-shadow: 0 0 20px #00ccff;
color: white;
}
</style>
</head>
<body>
<div style="display: flex; flex-direction: column; gap: 8px; width: min(900px, 95vw);">
<div class="info-bar">
<div class="info-item">🏆 <span id="scoreDisplay">0</span></div>
<div class="info-item">❤️ <span id="livesDisplay">3</span> | LEVEL <span id="levelDisplay">1</span></div>
<button class="btn-reset" id="restartBtn">↺ RESTART</button>
</div>
<canvas id="gameCanvas" width="900" height="600"></canvas>
<div style="text-align: center; color: #5f7a9a; font-size: 14px; padding-top: 6px; letter-spacing: 1px;">
← → / MOUSE MOVE · SPACE LAUNCH · P PAUSE
</div>
</div>
<script>
(function() {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreSpan = document.getElementById('scoreDisplay');
const livesSpan = document.getElementById('livesDisplay');
const levelSpan = document.getElementById('levelDisplay');
// ---------- GAME STATE ----------
let gameState = 'START'; // START, PLAYING, PAUSED, GAMEOVER, WIN
let score = 0;
let lives = 3;
let level = 1;
let ballSpeedMultiplier = 1.0;
// paddle
const paddle = {
width: 140,
height: 16,
x: 450 - 70,
y: 560,
color: '#00e5ff',
targetX: 450 - 70,
};
// ball
const ball = {
x: 450,
y: 530,
radius: 9,
dx: 3.2,
dy: -4.2,
speed: 5.2,
launched: false,
};
// bricks grid
let bricks = [];
const brickRows = 6;
const brickCols = 10;
const brickWidth = 70;
const brickHeight = 22;
const brickPadding = 8;
const brickOffsetTop = 60;
const brickOffsetLeft = 55;
// particles
let particles = [];
// power-ups (simple: multi-ball, wide paddle, slow)
let activePowerUps = {
multiBall: 0,
widePaddle: 0,
slowBall: 0,
};
let extraBalls = []; // for multi-ball
// audio (synthetic)
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function playTone(freq, duration, type = 'square', volume = 0.15) {
if (audioCtx.state === 'suspended') audioCtx.resume();
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = type;
osc.frequency.value = freq;
gain.gain.setValueAtTime(volume, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
osc.stop(audioCtx.currentTime + duration);
}
// ---------- INIT BRICKS ----------
function createBricks() {
bricks = [];
const colors = ['#ff4d6d', '#ff8c42', '#ffd166', '#4cc9f0', '#b5179e', '#4895ef'];
for (let r = 0; r < brickRows; r++) {
for (let c = 0; c < brickCols; c++) {
bricks.push({
x: brickOffsetLeft + c * (brickWidth + brickPadding),
y: brickOffsetTop + r * (brickHeight + brickPadding),
width: brickWidth,
height: brickHeight,
color: colors[r % colors.length],
alive: true,
glow: 0.8 + Math.random() * 0.4,
});
}
}
}
// ---------- RESET BALL & PADDLE ----------
function resetBall() {
ball.launched = false;
ball.x = paddle.x + paddle.width / 2;
ball.y = paddle.y - 12;
ball.dx = 3.2;
ball.dy = -4.2;
ball.speed = 5.2 * ballSpeedMultiplier;
extraBalls = [];
}
function resetGame() {
score = 0;
lives = 3;
level = 1;
ballSpeedMultiplier = 1.0;
paddle.width = 140;
paddle.x = 450 - 70;
paddle.targetX = paddle.x;
createBricks();
resetBall();
activePowerUps = { multiBall: 0, widePaddle: 0, slowBall: 0 };
particles = [];
gameState = 'START';
updateUI();
}
// ---------- UI UPDATE ----------
function updateUI() {
scoreSpan.textContent = score;
livesSpan.textContent = lives;
levelSpan.textContent = level;
}
// ---------- COLLISION & PHYSICS ----------
function ballBounce(ballObj) {
// walls
if (ballObj.x - ballObj.radius < 0) {
ballObj.x = ballObj.radius;
ballObj.dx = -ballObj.dx;
playTone(300, 0.08, 'triangle', 0.1);
}
if (ballObj.x + ballObj.radius > canvas.width) {
ballObj.x = canvas.width - ballObj.radius;
ballObj.dx = -ballObj.dx;
playTone(300, 0.08, 'triangle', 0.1);
}
if (ballObj.y - ballObj.radius < 0) {
ballObj.y = ballObj.radius;
ballObj.dy = -ballObj.dy;
playTone(400, 0.08, 'triangle', 0.1);
}
// paddle collision
if (ballObj.dy > 0 &&
ballObj.y + ballObj.radius >= paddle.y &&
ballObj.y + ballObj.radius <= paddle.y + paddle.height + 8 &&
ballObj.x >= paddle.x - ballObj.radius &&
ballObj.x <= paddle.x + paddle.width + ballObj.radius) {
// angle based on hit position
let hitPos = (ballObj.x - (paddle.x + paddle.width/2)) / (paddle.width/2);
hitPos = Math.max(-0.8, Math.min(0.8, hitPos));
let angle = hitPos * 0.6;
let speed = Math.hypot(ballObj.dx, ballObj.dy);
ballObj.dx = speed * Math.sin(angle);
ballObj.dy = -Math.abs(speed * Math.cos(angle));
ballObj.y = paddle.y - ballObj.radius - 1;
playTone(500, 0.1, 'sine', 0.12);
}
// bricks collision
for (let i = 0; i < bricks.length; i++) {
const b = bricks[i];
if (!b.alive) continue;
if (ballObj.x + ballObj.radius > b.x && ballObj.x - ballObj.radius < b.x + b.width &&
ballObj.y + ballObj.radius > b.y && ballObj.y - ballObj.radius < b.y + b.height) {
b.alive = false;
score += 10;
// particle burst
for (let p = 0; p < 14; p++) {
particles.push({
x: b.x + b.width/2,
y: b.y + b.height/2,
vx: (Math.random() - 0.5) * 8,
vy: (Math.random() - 0.5) * 8 - 2,
life: 1.0,
color: b.color,
size: 3 + Math.random() * 5
});
}
playTone(800 + Math.random() * 200, 0.12, 'square', 0.1);
// determine bounce direction
const overlapLeft = ballObj.x + ballObj.radius - b.x;
const overlapRight = b.x + b.width - (ballObj.x - ballObj.radius);
const overlapTop = ballObj.y + ballObj.radius - b.y;
const overlapBottom = b.y + b.height - (ballObj.y - ballObj.radius);
const minOverlap = Math.min(overlapLeft, overlapRight, overlapTop, overlapBottom);
if (minOverlap === overlapLeft || minOverlap === overlapRight) {
ballObj.dx = -ballObj.dx;
} else {
ballObj.dy = -ballObj.dy;
}
break; // only one brick per frame
}
}
// check win
if (bricks.every(b => !b.alive)) {
gameState = 'WIN';
playTone(1200, 0.4, 'sine', 0.2);
playTone(1600, 0.5, 'sine', 0.2);
}
}
// ---------- UPDATE ----------
function update() {
if (gameState !== 'PLAYING') return;
// paddle movement (keyboard handled in event, but mouse target)
paddle.x += (paddle.targetX - paddle.x) * 0.2;
paddle.x = Math.max(0, Math.min(canvas.width - paddle.width, paddle.x));
// main ball
if (!ball.launched) {
ball.x = paddle.x + paddle.width/2;
ball.y = paddle.y - 12;
} else {
ball.x += ball.dx * ballSpeedMultiplier;
ball.y += ball.dy * ballSpeedMultiplier;
ballBounce(ball);
}
// extra balls (multi-ball)
for (let i = extraBalls.length - 1; i >= 0; i--) {
const eb = extraBalls[i];
eb.x += eb.dx * ballSpeedMultiplier;
eb.y += eb.dy * ballSpeedMultiplier;
ballBounce(eb);
if (eb.y - eb.radius > canvas.height + 20) {
extraBalls.splice(i, 1);
}
}
// ball lost condition
if (ball.y - ball.radius > canvas.height + 20) {
lives--;
updateUI();
if (lives <= 0) {
gameState = 'GAMEOVER';
playTone(200, 0.5, 'sawtooth', 0.2);
} else {
resetBall();
}
}
// extra balls lost
for (let i = extraBalls.length - 1; i >= 0; i--) {
if (extraBalls[i].y - extraBalls[i].radius > canvas.height + 20) {
extraBalls.splice(i, 1);
}
}
// particles
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
p.x += p.vx;
p.y += p.vy;
p.vy += 0.15;
p.life -= 0.02;
if (p.life <= 0) particles.splice(i, 1);
}
// power-up timers (simplified)
if (activePowerUps.widePaddle > 0) {
activePowerUps.widePaddle--;
if (activePowerUps.widePaddle === 0) paddle.width = 140;
}
if (activePowerUps.slowBall > 0) {
activePowerUps.slowBall--;
if (activePowerUps.slowBall === 0) ballSpeedMultiplier = 1.0;
}
if (activePowerUps.multiBall > 0) {
activePowerUps.multiBall--;
if (activePowerUps.multiBall === 0) extraBalls = [];
}
// level progression (simple: every 500 points)
if (score > 0 && Math.floor(score / 500) > level - 1) {
level = Math.floor(score / 500) + 1;
levelSpan.textContent = level;
ballSpeedMultiplier = 1.0 + (level - 1) * 0.1;
// add some bricks back? no, just speed
}
}
// ---------- RENDER ----------
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// background grid
ctx.strokeStyle = '#1e2a44';
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.strokeStyle = '#1a2740';
ctx.stroke();
}
for (let i = 0; i < canvas.height; i += 40) {
ctx.beginPath();
ctx.moveTo(0, i);
ctx.lineTo(canvas.width, i);
ctx.strokeStyle = '#1a2740';
ctx.stroke();
}
// bricks
for (let b of bricks) {
if (!b.alive) continue;
const grad = ctx.createLinearGradient(b.x, b.y, b.x, b.y + b.height);
grad.addColorStop(0, b.color);
grad.addColorStop(1, '#1a1a3a');
ctx.fillStyle = grad;
ctx.shadowColor = b.color;
ctx.shadowBlur = 15;
ctx.fillRect(b.x, b.y, b.width, b.height);
ctx.shadowBlur = 0;
ctx.strokeStyle = '#ffffff30';
ctx.strokeRect(b.x, b.y, b.width, b.height);
}
// paddle
ctx.shadowColor = '#00e5ff';
ctx.shadowBlur = 20;
ctx.fillStyle = '#00e5ff';
ctx.beginPath();
ctx.roundRect(paddle.x, paddle.y, paddle.width, paddle.height, 8);
ctx.fill();
ctx.shadowBlur = 0;
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.roundRect(paddle.x + 4, paddle.y + 2, paddle.width - 8, 4, 4);
ctx.fill();
// ball (main)
ctx.shadowColor = '#ffaa00';
ctx.shadowBlur = 20;
ctx.fillStyle = '#ffd966';
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
// extra balls
for (let eb of extraBalls) {
ctx.fillStyle = '#ffaa66';
ctx.shadowColor = '#ff8800';
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.arc(eb.x, eb.y, ball.radius, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
}
// particles
for (let p of particles) {
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;
// overlays
if (gameState === 'START') {
ctx.fillStyle = '#000000aa';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 42px "Segoe UI", sans-serif';
ctx.textAlign = 'center';
ctx.shadowColor = '#00ccff';
ctx.shadowBlur = 30;
ctx.fillText('NEON BREAKOUT', canvas.width/2, 220);
ctx.font = '24px sans-serif';
ctx.fillStyle = '#aaf0ff';
ctx.fillText('PRESS SPACE TO START', canvas.width/2, 320);
ctx.shadowBlur = 0;
}
if (gameState === 'PAUSED') {
ctx.fillStyle = '#00000088';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 40px sans-serif';
ctx.fillText('⏸ PAUSED', canvas.width/2, 300);
ctx.font = '20px sans-serif';
ctx.fillText('PRESS P TO RESUME', canvas.width/2, 360);
}
if (gameState === 'GAMEOVER') {
ctx.fillStyle = '#000000bb';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ff4d6d';
ctx.font = 'bold 46px sans-serif';
ctx.fillText('GAME OVER', canvas.width/2, 280);
ctx.fillStyle = '#ffffff';
ctx.font = '24px sans-serif';
ctx.fillText(`SCORE: ${score}`, canvas.width/2, 340);
ctx.fillText('CLICK RESTART', canvas.width/2, 400);
}
if (gameState === 'WIN') {
ctx.fillStyle = '#000000aa';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffd166';
ctx.font = 'bold 46px sans-serif';
ctx.fillText('🏆 YOU WIN!', canvas.width/2, 280);
ctx.fillStyle = '#ffffff';
ctx.font = '24px sans-serif';
ctx.fillText(`SCORE: ${score}`, canvas.width/2, 340);
}
}
// 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;
};
// ---------- GAME LOOP ----------
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
// ---------- EVENT LISTENERS ----------
// mouse
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const mouseX = (e.clientX - rect.left) * scaleX;
paddle.targetX = mouseX - paddle.width / 2;
});
// keyboard
window.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
paddle.targetX = Math.max(0, paddle.x - 30);
e.preventDefault();
}
if (e.key === 'ArrowRight') {
paddle.targetX = Math.min(canvas.width - paddle.width, paddle.x + 30);
e.preventDefault();
}
if (e.key === ' ') {
e.preventDefault();
if (gameState === 'START') {
gameState = 'PLAYING';
ball.launched = true;
playTone(600, 0.1, 'sine');
} else if (gameState === 'PLAYING' && !ball.launched) {
ball.launched = true;
playTone(600, 0.1, 'sine');
}
}
if (e.key === 'p' || e.key === 'P') {
if (gameState === 'PLAYING') {
gameState = 'PAUSED';
} else if (gameState === 'PAUSED') {
gameState = 'PLAYING';
}
}
});
// restart button
document.getElementById('restartBtn').addEventListener('click', () => {
resetGame();
gameState = 'START';
});
// initial setup
createBricks();
resetBall();
updateUI();
gameLoop();
// power-up simulation (random every 20 seconds)
setInterval(() => {
if (gameState !== 'PLAYING') return;
const rand = Math.random();
if (rand < 0.4) {
activePowerUps.widePaddle = 600;
paddle.width = 200;
} else if (rand < 0.7) {
activePowerUps.slowBall = 500;
ballSpeedMultiplier = 0.7;
} else {
if (extraBalls.length < 3) {
for (let i = 0; i < 2; i++) {
extraBalls.push({
x: ball.x, y: ball.y,
dx: (Math.random() - 0.5) * 6,
dy: -Math.random() * 5 - 2,
radius: 8,
});
}
activePowerUps.multiBall = 300;
}
}
}, 15000);
})();
</script>
</body>
</html>
Melde dich an, um den vollständigen Prompt zu sehen
Weiter mit:
Mit der Anmeldung akzeptierst du unsere Nutzungsbedingungen und Datenschutz
Verwendung
Dieser Prompt ist für die Verwendung mit coding gedacht. Kopiere den Inhalt oben und füge ihn in dein bevorzugtes KI-Tool ein.
Für beste Ergebnisse passe die Platzhalter (eckige Klammern oder Großbuchstaben) an deine Anforderungen an.
Referenzen
- Kategorie: coding-Prompts
- Quelle: https://x.com/eyishazyer/status/2075850024164950156
Diskussion
0 Kommentare