brickbreakergame / index.html
offerpk3's picture
Update index.html
ec37170 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bricks vs Balls - Ultimate Brick Breaker</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: linear-gradient(135deg, #1e3c72, #2a5298);
font-family: 'Arial', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow: hidden;
}
.game-container {
position: relative;
background: rgba(0, 0, 0, 0.8);
border-radius: 20px;
padding: 20px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
}
canvas {
border: 3px solid #00ffff;
border-radius: 15px;
background: linear-gradient(180deg, #000428, #004e92);
box-shadow: inset 0 0 50px rgba(0, 255, 255, 0.1);
}
.ui {
position: absolute;
top: 10px;
left: 20px;
color: #00ffff;
font-size: 18px;
font-weight: bold;
text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
}
.controls {
position: absolute;
bottom: -50px;
left: 50%;
transform: translateX(-50%);
color: #fff;
text-align: center;
font-size: 14px;
opacity: 0.8;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.9);
color: #00ffff;
padding: 30px;
border-radius: 15px;
text-align: center;
border: 2px solid #00ffff;
box-shadow: 0 0 30px rgba(0, 255, 255, 0.3);
display: none;
}
.restart-btn {
background: linear-gradient(45deg, #00ffff, #0080ff);
border: none;
color: #000;
padding: 12px 25px;
font-size: 16px;
font-weight: bold;
border-radius: 25px;
cursor: pointer;
margin-top: 15px;
transition: all 0.3s ease;
}
.restart-btn:hover {
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(0, 255, 255, 0.4);
}
.power-indicator {
position: absolute;
bottom: 20px;
left: 20px;
color: #ffff00;
font-size: 14px;
opacity: 0;
transition: opacity 0.3s ease;
}
</style>
</head>
<body>
<div class="game-container">
<div class="ui">
<div>Score: <span id="score">0</span></div>
<div>Level: <span id="level">1</span></div>
<div>Balls: <span id="balls">1</span></div>
</div>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<div class="power-indicator" id="powerIndicator">
Power: <span id="powerValue">0</span>%
</div>
<div class="controls">
Mouse: Aim & Shoot | Space: Quick Restart | Click: Fire Balls
</div>
<div class="game-over" id="gameOver">
<h2>Game Over!</h2>
<p>Final Score: <span id="finalScore">0</span></p>
<p>Level Reached: <span id="finalLevel">1</span></p>
<button class="restart-btn" onclick="restartGame()">Play Again</button>
</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const levelEl = document.getElementById('level');
const ballsEl = document.getElementById('balls');
const gameOverEl = document.getElementById('gameOver');
const powerIndicator = document.getElementById('powerIndicator');
const powerValue = document.getElementById('powerValue');
let gameState = {
score: 0,
level: 1,
ballCount: 1,
isAiming: false,
isShooting: false,
gameOver: false,
mouseX: 0,
mouseY: 0,
launchPower: 0
};
let balls = [];
let bricks = [];
let powerUps = [];
let particles = [];
const BALL_RADIUS = 8;
const BALL_SPEED = 8;
const BRICK_WIDTH = 60;
const BRICK_HEIGHT = 30;
const BRICK_ROWS = 6;
const BRICK_COLS = 12;
class Ball {
constructor(x, y, vx = 0, vy = 0) {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.radius = BALL_RADIUS;
this.trail = [];
this.active = true;
}
update() {
if (!this.active) return;
this.trail.push({x: this.x, y: this.y});
if (this.trail.length > 10) this.trail.shift();
this.x += this.vx;
this.y += this.vy;
// Wall collisions
if (this.x <= this.radius || this.x >= canvas.width - this.radius) {
this.vx = -this.vx;
this.x = Math.max(this.radius, Math.min(canvas.width - this.radius, this.x));
createImpactParticles(this.x, this.y, '#00ffff');
}
if (this.y <= this.radius) {
this.vy = -this.vy;
this.y = this.radius;
createImpactParticles(this.x, this.y, '#00ffff');
}
// Bottom boundary - ball returns to launch position
if (this.y > canvas.height) {
this.active = false;
}
// Brick collisions
for (let i = bricks.length - 1; i >= 0; i--) {
const brick = bricks[i];
if (this.collidesWith(brick)) {
this.handleBrickCollision(brick);
gameState.score += brick.hits * 10;
brick.hits--;
createImpactParticles(this.x, this.y, brick.color);
if (brick.hits <= 0) {
// Chance for power-up
if (Math.random() < 0.1) {
powerUps.push(new PowerUp(brick.x + brick.width/2, brick.y + brick.height/2));
}
bricks.splice(i, 1);
}
break;
}
}
}
collidesWith(brick) {
const closestX = Math.max(brick.x, Math.min(this.x, brick.x + brick.width));
const closestY = Math.max(brick.y, Math.min(this.y, brick.y + brick.height));
const distance = Math.sqrt((this.x - closestX) ** 2 + (this.y - closestY) ** 2);
return distance < this.radius;
}
handleBrickCollision(brick) {
const brickCenterX = brick.x + brick.width / 2;
const brickCenterY = brick.y + brick.height / 2;
const dx = this.x - brickCenterX;
const dy = this.y - brickCenterY;
if (Math.abs(dx) > Math.abs(dy)) {
this.vx = -this.vx;
} else {
this.vy = -this.vy;
}
}
draw() {
if (!this.active) return;
// Draw trail
ctx.globalAlpha = 0.6;
for (let i = 0; i < this.trail.length; i++) {
const alpha = i / this.trail.length;
const size = this.radius * alpha;
ctx.beginPath();
ctx.arc(this.trail[i].x, this.trail[i].y, size, 0, Math.PI * 2);
ctx.fillStyle = `rgba(0, 255, 255, ${alpha * 0.3})`;
ctx.fill();
}
ctx.globalAlpha = 1;
// Draw ball with glow effect
ctx.shadowColor = '#00ffff';
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
const gradient = ctx.createRadialGradient(this.x-3, this.y-3, 0, this.x, this.y, this.radius);
gradient.addColorStop(0, '#ffffff');
gradient.addColorStop(0.3, '#00ffff');
gradient.addColorStop(1, '#0080ff');
ctx.fillStyle = gradient;
ctx.fill();
ctx.shadowBlur = 0;
}
}
class Brick {
constructor(x, y, hits) {
this.x = x;
this.y = y;
this.width = BRICK_WIDTH;
this.height = BRICK_HEIGHT;
this.hits = hits;
this.maxHits = hits;
this.color = this.getColorByHits(hits);
this.pulsePhase = Math.random() * Math.PI * 2;
}
getColorByHits(hits) {
const colors = ['#ff4444', '#ff8844', '#ffaa44', '#ffff44', '#88ff44', '#44ff88'];
return colors[Math.min(hits - 1, colors.length - 1)];
}
update() {
this.pulsePhase += 0.05;
this.color = this.getColorByHits(this.hits);
}
draw() {
const pulse = Math.sin(this.pulsePhase) * 0.1 + 0.9;
ctx.shadowColor = this.color;
ctx.shadowBlur = 10 * pulse;
// Main brick
ctx.fillStyle = this.color;
ctx.fillRect(this.x + 2, this.y + 2, this.width - 4, this.height - 4);
// Highlight
const gradient = ctx.createLinearGradient(this.x, this.y, this.x, this.y + this.height);
gradient.addColorStop(0, 'rgba(255, 255, 255, 0.3)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
ctx.fillStyle = gradient;
ctx.fillRect(this.x + 2, this.y + 2, this.width - 4, this.height/2 - 2);
// Hit counter
ctx.shadowBlur = 0;
ctx.fillStyle = '#000';
ctx.font = 'bold 14px Arial';
ctx.textAlign = 'center';
ctx.fillText(this.hits, this.x + this.width/2, this.y + this.height/2 + 5);
}
}
class PowerUp {
constructor(x, y) {
this.x = x;
this.y = y;
this.radius = 15;
this.vy = 2;
this.type = Math.random() < 0.5 ? 'multi' : 'power';
this.rotation = 0;
}
update() {
this.y += this.vy;
this.rotation += 0.1;
if (this.y > canvas.height) {
return false;
}
// Check collision with launch area
if (this.y > canvas.height - 50 && Math.abs(this.x - canvas.width/2) < 50) {
this.activate();
return false;
}
return true;
}
activate() {
if (this.type === 'multi') {
gameState.ballCount++;
} else {
// Power boost - temporary effect
gameState.score += 50;
}
createImpactParticles(this.x, this.y, '#ffff00');
}
draw() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
ctx.shadowColor = '#ffff00';
ctx.shadowBlur = 15;
ctx.fillStyle = this.type === 'multi' ? '#ffff00' : '#ff8800';
ctx.beginPath();
ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'center';
ctx.fillText(this.type === 'multi' ? '+' : '⚡', 0, 4);
ctx.restore();
}
}
class Particle {
constructor(x, y, color) {
this.x = x;
this.y = y;
this.vx = (Math.random() - 0.5) * 8;
this.vy = (Math.random() - 0.5) * 8;
this.life = 1;
this.decay = 0.02;
this.color = color;
this.size = Math.random() * 4 + 2;
}
update() {
this.x += this.vx;
this.y += this.vy;
this.life -= this.decay;
this.size *= 0.98;
return this.life > 0;
}
draw() {
ctx.globalAlpha = this.life;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1;
}
}
function createImpactParticles(x, y, color) {
for (let i = 0; i < 8; i++) {
particles.push(new Particle(x, y, color));
}
}
function initLevel() {
bricks = [];
const padding = 20;
const totalWidth = BRICK_COLS * BRICK_WIDTH + (BRICK_COLS - 1) * 5;
const startX = (canvas.width - totalWidth) / 2;
for (let row = 0; row < BRICK_ROWS; row++) {
for (let col = 0; col < BRICK_COLS; col++) {
const x = startX + col * (BRICK_WIDTH + 5);
const y = padding + row * (BRICK_HEIGHT + 5);
const hits = Math.min(gameState.level + row, 6);
bricks.push(new Brick(x, y, hits));
}
}
}
function launchBalls() {
if (gameState.isShooting || balls.some(b => b.active)) return;
const launchX = canvas.width / 2;
const launchY = canvas.height - 30;
const angle = Math.atan2(gameState.mouseY - launchY, gameState.mouseX - launchX);
const speed = BALL_SPEED;
gameState.isShooting = true;
for (let i = 0; i < gameState.ballCount; i++) {
setTimeout(() => {
const vx = Math.cos(angle) * speed;
const vy = Math.sin(angle) * speed;
balls.push(new Ball(launchX, launchY, vx, vy));
}, i * 100);
}
}
function updateGame() {
if (gameState.gameOver) return;
// Update balls
balls = balls.filter(ball => {
ball.update();
return ball.active;
});
// Update bricks
bricks.forEach(brick => brick.update());
// Update power-ups
powerUps = powerUps.filter(powerUp => powerUp.update());
// Update particles
particles = particles.filter(particle => particle.update());
// Check if all balls are done and ready for next shot
if (gameState.isShooting && balls.length === 0) {
gameState.isShooting = false;
}
// Check level completion
if (bricks.length === 0) {
gameState.level++;
gameState.ballCount++;
initLevel();
}
// Check game over (simplified)
if (gameState.score < 0) {
gameState.gameOver = true;
showGameOver();
}
updateUI();
}
function drawGame() {
// Clear canvas with gradient
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, '#000428');
gradient.addColorStop(1, '#004e92');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw aiming line
if (gameState.isAiming && !gameState.isShooting) {
drawAimingLine();
}
// Draw game objects
bricks.forEach(brick => brick.draw());
balls.forEach(ball => ball.draw());
powerUps.forEach(powerUp => powerUp.draw());
particles.forEach(particle => particle.draw());
// Draw launch position
if (!gameState.isShooting && balls.length === 0) {
ctx.shadowColor = '#00ffff';
ctx.shadowBlur = 10;
ctx.fillStyle = '#00ffff';
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height - 30, 10, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
}
}
function drawAimingLine() {
const launchX = canvas.width / 2;
const launchY = canvas.height - 30;
ctx.setLineDash([5, 5]);
ctx.strokeStyle = '#00ffff';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(launchX, launchY);
ctx.lineTo(gameState.mouseX, gameState.mouseY);
ctx.stroke();
ctx.setLineDash([]);
// Show power indicator
const distance = Math.sqrt((gameState.mouseX - launchX) ** 2 + (gameState.mouseY - launchY) ** 2);
const power = Math.min(distance / 200, 1) * 100;
powerValue.textContent = Math.round(power);
powerIndicator.style.opacity = '1';
}
function updateUI() {
scoreEl.textContent = gameState.score;
levelEl.textContent = gameState.level;
ballsEl.textContent = gameState.ballCount;
}
function showGameOver() {
document.getElementById('finalScore').textContent = gameState.score;
document.getElementById('finalLevel').textContent = gameState.level;
gameOverEl.style.display = 'block';
}
function restartGame() {
gameState = {
score: 0,
level: 1,
ballCount: 1,
isAiming: false,
isShooting: false,
gameOver: false,
mouseX: 0,
mouseY: 0,
launchPower: 0
};
balls = [];
bricks = [];
powerUps = [];
particles = [];
gameOverEl.style.display = 'none';
powerIndicator.style.opacity = '0';
initLevel();
updateUI();
}
// Event listeners
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
gameState.mouseX = e.clientX - rect.left;
gameState.mouseY = e.clientY - rect.top;
gameState.isAiming = !gameState.isShooting && balls.length === 0;
});
canvas.addEventListener('mouseleave', () => {
gameState.isAiming = false;
powerIndicator.style.opacity = '0';
});
canvas.addEventListener('click', () => {
if (!gameState.gameOver && !gameState.isShooting && balls.length === 0) {
launchBalls();
powerIndicator.style.opacity = '0';
}
});
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
e.preventDefault();
if (gameState.gameOver) {
restartGame();
} else if (!gameState.isShooting && balls.length === 0) {
launchBalls();
}
}
});
// Game loop
function gameLoop() {
updateGame();
drawGame();
requestAnimationFrame(gameLoop);
}
// Initialize game
initLevel();
updateUI();
gameLoop();
</script>
</body>
</html>