Break Tris
Break Tris
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Break Tris Game</title> <style> canvas { background: #000; display: block; margin: 0 auto; } </style> </head> <body> <canvas id="gameCanvas" width="480" height="640"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const ROWS = 20; const COLS = 10; const BLOCK_SIZE = 30; let gameStage = 1; // 1: Breakout, 2: Shooting let score = 0; // ==================== Breakout setup ==================== class Ball { constructor() { this.x = canvas.width / 2; this.y = canvas.height - 60; this.radius = 8; this.speedX = 4 * (Math.random() > 0.5 ? 1 : -1); this.speedY = -4; } move() { this.x += this.speedX; this.y += this.speedY; if (this.x + this.radius > canvas.width || this.x - this.radius < 0) { this.speedX *= -1; } if (this.y - this.radius < 0) { this.speedY *= -1; } } draw() { ctx.fillStyle = "white"; ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2); ctx.fill(); } } class Paddle { constructor() { this.width = 75; this.height = 10; this.x = (canvas.width - this.width) / 2; this.y = canvas.height - 50; this.speed = 7; this.moveLeft = false; this.moveRight = false; } move() { if (this.moveLeft && this.x > 0) this.x -= this.speed; if (this.moveRight && this.x + this.width < canvas.width) this.x += this.speed; } draw() { ctx.fillStyle = "white"; ctx.fillRect(this.x, this.y, this.width, this.height); } } class Brick { constructor(x, y, active=true) { this.x = x; this.y = y; this.width = BLOCK_SIZE; this.height = BLOCK_SIZE/2; this.active = active; } draw() { if (this.active) { ctx.fillStyle = "red"; ctx.fillRect(this.x, this.y, this.width, this.height); } } } const ball = new Ball(); const paddle = new Paddle(); const bricks = []; for (let r=0; r<5; r++) { for (let c=0; c<COLS; c++) { bricks.push(new Brick(c*BLOCK_SIZE + 10, r*BLOCK_SIZE/2 + 30)); } } // ==================== Shooting setup ==================== let remainingBricks = []; function initBricks() { remainingBricks = bricks.filter(b => b.active); } class Shooter { constructor() { this.x = canvas.width/2; this.y = canvas.height - 50; this.width = 10; this.height = 20; this.speed = 5; this.shooting = false; } move() { if (keys['ArrowLeft']) this.x -= this.speed; if (keys['ArrowRight']) this.x += this.speed; if (this.x <0) this.x=0; if (this.x + this.width > canvas.width) this.x=canvas.width - this.width; } draw() { ctx.fillStyle = "yellow"; ctx.fillRect(this.x, this.y, this.width, this.height); } shoot() { return new Bullet(this.x + this.width/2, this.y); } } class Bullet { constructor(x, y) { this.x = x; this.y = y; this.speedY = -8; } move() { this.y += this.speedY; } draw() { ctx.fillStyle = "white"; ctx.fillRect(this.x-2, this.y, 4, 10); } offScreen() { return this.y + 10 < 0; } hits(brick) { return this.x > brick.x && this.x < brick.x + brick.width && this.y < brick.y + brick.height && this.y + 10 > brick.y; } } const shooter = new Shooter(); let bullets = []; // ===================== Controls ========================= const keys = {}; document.addEventListener('keydown', e => { keys[e.key] = true; }); document.addEventListener('keyup', e => { keys[e.key] = false; }); canvas.addEventListener('mousemove', e => { if (gameStage === 1) { paddle.x = e.offsetX - paddle.width/2; } }); document.addEventListener('click', () => { if (gameStage === 2) { bullets.push(shooter.shoot()); } }); // ==================== Game Loop =================== function gameLoop() { ctx.clearRect(0, 0, canvas.width, canvas.height); if (gameStage === 1) { // Breakout stage paddle.move(); ball.move(); // collision with paddle if (ball.y + ball.radius > paddle.y && ball.x > paddle.x && ball.x < paddle.x + paddle.width) { ball.speedY *= -1; } // collision with bricks for (let brick of bricks) { if (brick.active && ball.x > brick.x && ball.x < brick.x + brick.width && ball.y - ball.radius < brick.y + brick.height && ball.y + ball.radius > brick.y) { brick.active = false; ball.speedY *= -1; score++; break; } } // check for stage complete if (bricks.every(b => !b.active)) { gameStage = 2; initBricks(); } // check for lose if (ball.y - ball.radius > canvas.height) { alert('Game Over! Your score: ' + score); document.location.reload(); } ball.draw(); paddle.draw(); } else if (gameStage === 2) { // Shooting stage shooter.move(); shooter.draw(); bullets.forEach(bullet => { bullet.move(); bullet.draw(); }); bullets = bullets.filter(b => !b.offScreen()); // Check hits for (let b of bullets) { for (let brick of remainingBricks) { if (brick.active && b.hits(brick)) { brick.active = false; } } } // Check stage completion if (remainingBricks.every(b => !b.active)) { alert('Congratulations! You completed both stages.'); document.location.reload(); } } // Draw remaining bricks in stage 2 if (gameStage === 2) { for (let brick of remainingBricks) { brick.draw(); } } requestAnimationFrame(gameLoop); } setInterval(() => { if (gameStage === 1) { // nothing extra here } }, 1000); // assign remaining bricks for stage 2 // Already initialized in initBricks gameLoop(); </script> </body> </html>