Files
HTML-Game/breakout.html
T
2026-05-28 18:47:18 +03:00

154 lines
5.3 KiB
HTML

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Breakout</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #0a0a1a;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
font-family: 'Segoe UI', sans-serif;
color: #eee;
}
h1 { color: #00bfff; margin-bottom: 10px; text-shadow: 0 0 15px #00bfff; }
#stats { display: flex; gap: 20px; margin-bottom: 10px; font-size: 1.1em; }
canvas { border: 2px solid #00bfff; border-radius: 8px; box-shadow: 0 0 30px rgba(0,191,255,0.3); cursor: none; }
#info { margin-top: 10px; color: #888; }
</style>
</head>
<body>
<h1>🧱 Breakout</h1>
<div id="stats"><span>Счёт: <b id="sc">0</b></span><span>Жизни: <b id="lv">3</b></span></div>
<canvas id="game" width="480" height="360"></canvas>
<div id="info">Мышь / стрелки — управление платформой</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;
let paddle, ball, bricks, score, lives, running, animId;
const brickRows = 5, brickCols = 8, brickW = 52, brickH = 18, brickPad = 5, brickOffTop = 30, brickOffLeft = 14;
const colors = ['#ff0040','#ff8800','#ffdd00','#00cc44','#0088ff'];
function init() {
paddle = { x: W / 2 - 40, y: H - 25, w: 80, h: 12 };
ball = { x: W / 2, y: H - 40, r: 7, dx: 3, dy: -3 };
score = 0; lives = 3;
bricks = [];
for (let r = 0; r < brickRows; r++)
for (let c = 0; c < brickCols; c++)
bricks.push({ x: brickOffLeft + c * (brickW + brickPad), y: brickOffTop + r * (brickH + brickPad), w: brickW, h: brickH, alive: true, color: colors[r] });
running = true;
document.getElementById('sc').textContent = 0;
document.getElementById('lv').textContent = 3;
cancelAnimationFrame(animId);
loop();
}
function loop() {
update();
draw();
if (running) animId = requestAnimationFrame(loop);
}
function update() {
if (!running) return;
ball.x += ball.dx;
ball.y += ball.dy;
if (ball.x - ball.r < 0 || ball.x + ball.r > W) ball.dx *= -1;
if (ball.y - ball.r < 0) ball.dy *= -1;
if (ball.y + ball.r > H) {
lives--;
document.getElementById('lv').textContent = lives;
if (lives <= 0) { running = false; return; }
ball.x = W / 2; ball.y = H - 40; ball.dx = 3 * (Math.random() > 0.5 ? 1 : -1); ball.dy = -3;
}
if (ball.y + ball.r >= paddle.y && ball.y + ball.r <= paddle.y + paddle.h &&
ball.x >= paddle.x && ball.x <= paddle.x + paddle.w) {
ball.dy = -Math.abs(ball.dy);
let hit = (ball.x - paddle.x) / paddle.w - 0.5;
ball.dx = hit * 6;
}
bricks.forEach(b => {
if (!b.alive) return;
if (ball.x + ball.r > b.x && ball.x - ball.r < b.x + b.w &&
ball.y + ball.r > b.y && ball.y - ball.r < b.y + b.h) {
b.alive = false;
ball.dy *= -1;
score += 10;
document.getElementById('sc').textContent = score;
}
});
if (bricks.every(b => !b.alive)) { running = false; }
}
function draw() {
ctx.fillStyle = '#0a0a1a';
ctx.fillRect(0, 0, W, H);
bricks.forEach(b => {
if (!b.alive) return;
ctx.fillStyle = b.color;
ctx.shadowColor = b.color;
ctx.shadowBlur = 8;
ctx.fillRect(b.x, b.y, b.w, b.h);
});
ctx.shadowBlur = 0;
ctx.fillStyle = '#00bfff';
ctx.shadowColor = '#00bfff';
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
const pg = ctx.createLinearGradient(paddle.x, 0, paddle.x + paddle.w, 0);
pg.addColorStop(0, '#00bfff');
pg.addColorStop(1, '#0066cc');
ctx.fillStyle = pg;
ctx.shadowColor = '#00bfff';
ctx.shadowBlur = 10;
ctx.fillRect(paddle.x, paddle.y, paddle.w, paddle.h);
ctx.shadowBlur = 0;
if (!running) {
ctx.fillStyle = 'rgba(0,0,0,0.6)';
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#00bfff';
ctx.font = 'bold 30px Segoe UI';
ctx.textAlign = 'center';
const msg = bricks.every(b => !b.alive) ? '🎉 ПОБЕДА!' : 'GAME OVER';
ctx.fillText(msg, W / 2, H / 2 - 10);
ctx.fillStyle = '#fff';
ctx.font = '18px Segoe UI';
ctx.fillText('Счёт: ' + score + ' | Клик — заново', W / 2, H / 2 + 25);
}
}
canvas.addEventListener('mousemove', e => {
const rect = canvas.getBoundingClientRect();
paddle.x = (e.clientX - rect.left) * (W / rect.width) - paddle.w / 2;
paddle.x = Math.max(0, Math.min(W - paddle.w, paddle.x));
});
canvas.addEventListener('touchmove', e => {
e.preventDefault();
const rect = canvas.getBoundingClientRect();
paddle.x = (e.touches[0].clientX - rect.left) * (W / rect.width) - paddle.w / 2;
paddle.x = Math.max(0, Math.min(W - paddle.w, paddle.x));
}, { passive: false });
document.addEventListener('keydown', e => {
if (e.key === 'ArrowLeft') paddle.x = Math.max(0, paddle.x - 20);
if (e.key === 'ArrowRight') paddle.x = Math.min(W - paddle.w, paddle.x + 20);
});
canvas.addEventListener('click', () => { if (!running) init(); });
init();
</script>
</body>
</html>