Spaces:
Running
Running
<html lang="fr"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>200K Brick Breaker - YouTube Celebration</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap'); | |
body { | |
font-family: 'Poppins', sans-serif; | |
background: linear-gradient(135deg, #1a1a2e, #16213e); | |
overflow: hidden; | |
} | |
#gameCanvas { | |
box-shadow: 0 0 30px rgba(0, 150, 255, 0.5); | |
border-radius: 10px; | |
} | |
.brick { | |
transition: all 0.2s ease; | |
} | |
.brick-hit { | |
animation: hit 0.3s ease; | |
} | |
@keyframes hit { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.1); } | |
100% { transform: scale(1); } | |
} | |
.confetti { | |
position: absolute; | |
width: 10px; | |
height: 10px; | |
background-color: #f00; | |
border-radius: 50%; | |
pointer-events: none; | |
} | |
</style> | |
</head> | |
<body class="min-h-screen flex flex-col items-center justify-center text-white"> | |
<div class="text-center mb-6"> | |
<h1 class="text-4xl font-bold mb-2 bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-600"> | |
Brick Breaker 200K | |
</h1> | |
<p class="text-lg text-blue-200">Cassez les briques pour célébrer nos 200 000 abonnés !</p> | |
</div> | |
<div class="relative"> | |
<canvas id="gameCanvas" width="800" height="500" class="bg-gray-900 border-2 border-blue-500"></canvas> | |
<div id="startScreen" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-70"> | |
<div class="text-center p-8 rounded-xl bg-gray-800 border border-blue-500 max-w-md"> | |
<i class="fas fa-gamepad text-5xl text-blue-400 mb-4"></i> | |
<h2 class="text-2xl font-bold mb-4">Brick Breaker 200K</h2> | |
<p class="mb-6">Utilisez les flèches ou la souris pour déplacer la raquette et cassez toutes les briques !</p> | |
<button id="startButton" class="px-6 py-3 bg-gradient-to-r from-blue-500 to-purple-600 rounded-full font-bold hover:from-blue-600 hover:to-purple-700 transition-all transform hover:scale-105 shadow-lg"> | |
COMMENCER LE JEU | |
</button> | |
</div> | |
</div> | |
<div id="gameOverScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-70"> | |
<div class="text-center p-8 rounded-xl bg-gray-800 border border-blue-500 max-w-md"> | |
<i class="fas fa-trophy text-5xl text-yellow-400 mb-4"></i> | |
<h2 id="resultTitle" class="text-2xl font-bold mb-2">Félicitations !</h2> | |
<p id="resultMessage" class="mb-4">Vous avez cassé toutes les briques des 200K abonnés !</p> | |
<div class="flex justify-center space-x-4"> | |
<button id="restartButton" class="px-4 py-2 bg-blue-500 rounded-full font-bold hover:bg-blue-600 transition"> | |
Rejouer | |
</button> | |
<button id="shareButton" class="px-4 py-2 bg-purple-500 rounded-full font-bold hover:bg-purple-600 transition"> | |
<i class="fas fa-share mr-2"></i>Partager | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="mt-6 flex items-center space-x-8"> | |
<div class="flex items-center space-x-2"> | |
<i class="fas fa-heart text-red-500"></i> | |
<span id="lives">3</span> | |
</div> | |
<div class="flex items-center space-x-2"> | |
<i class="fas fa-bolt text-yellow-400"></i> | |
<span id="score">0</span> | |
</div> | |
<div class="flex items-center space-x-2"> | |
<i class="fas fa-layer-group text-blue-400"></i> | |
<span id="level">1</span> | |
</div> | |
</div> | |
<div class="mt-8 text-center text-blue-300"> | |
<p>Merci à nos 200 000 abonnés ! Abonnez-vous pour plus de jeux amusants.</p> | |
<div class="mt-2 flex justify-center space-x-4"> | |
<button class="px-4 py-2 bg-red-600 rounded-full font-bold hover:bg-red-700 transition flex items-center"> | |
<i class="fab fa-youtube mr-2"></i> YouTube | |
</button> | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', () => { | |
// Canvas setup | |
const canvas = document.getElementById('gameCanvas'); | |
const ctx = canvas.getContext('2d'); | |
// Game elements | |
const paddle = { | |
width: 100, | |
height: 15, | |
x: canvas.width / 2 - 50, | |
speed: 8, | |
isMoving: false, | |
direction: 0 | |
}; | |
const ball = { | |
x: canvas.width / 2, | |
y: canvas.height - 30, | |
radius: 8, | |
dx: 4, | |
dy: -4, | |
speed: 4 | |
}; | |
// Game state | |
let lives = 3; | |
let score = 0; | |
let level = 1; | |
let gameRunning = false; | |
let bricks = []; | |
let brickRowCount = 5; | |
let brickColumnCount = 10; | |
let brickWidth = 75; | |
let brickHeight = 20; | |
let brickPadding = 10; | |
let brickOffsetTop = 60; | |
let brickOffsetLeft = 30; | |
// DOM elements | |
const livesDisplay = document.getElementById('lives'); | |
const scoreDisplay = document.getElementById('score'); | |
const levelDisplay = document.getElementById('level'); | |
const startScreen = document.getElementById('startScreen'); | |
const gameOverScreen = document.getElementById('gameOverScreen'); | |
const startButton = document.getElementById('startButton'); | |
const restartButton = document.getElementById('restartButton'); | |
const shareButton = document.getElementById('shareButton'); | |
const resultTitle = document.getElementById('resultTitle'); | |
const resultMessage = document.getElementById('resultMessage'); | |
// Initialize bricks | |
function initBricks() { | |
bricks = []; | |
const colors = ['#FF5252', '#FFD740', '#69F0AE', '#40C4FF', '#E040FB']; | |
for (let c = 0; c < brickColumnCount; c++) { | |
bricks[c] = []; | |
for (let r = 0; r < brickRowCount; r++) { | |
const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft; | |
const brickY = r * (brickHeight + brickPadding) + brickOffsetTop; | |
const colorIndex = Math.floor(Math.random() * colors.length); | |
bricks[c][r] = { | |
x: brickX, | |
y: brickY, | |
status: 1, | |
color: colors[colorIndex], | |
hit: false | |
}; | |
} | |
} | |
} | |
// Draw paddle | |
function drawPaddle() { | |
ctx.beginPath(); | |
ctx.rect(paddle.x, canvas.height - paddle.height, paddle.width, paddle.height); | |
ctx.fillStyle = '#3D5AFE'; | |
ctx.fill(); | |
ctx.closePath(); | |
// Add gradient effect | |
const gradient = ctx.createLinearGradient(paddle.x, 0, paddle.x + paddle.width, 0); | |
gradient.addColorStop(0, '#3D5AFE'); | |
gradient.addColorStop(1, '#2962FF'); | |
ctx.fillStyle = gradient; | |
ctx.fill(); | |
// Add shine effect | |
ctx.beginPath(); | |
ctx.moveTo(paddle.x + 5, canvas.height - paddle.height); | |
ctx.lineTo(paddle.x + paddle.width - 5, canvas.height - paddle.height); | |
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; | |
ctx.lineWidth = 2; | |
ctx.stroke(); | |
} | |
// Draw ball | |
function drawBall() { | |
ctx.beginPath(); | |
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2); | |
// Add gradient to ball | |
const gradient = ctx.createRadialGradient( | |
ball.x - ball.radius / 3, | |
ball.y - ball.radius / 3, | |
ball.radius / 3, | |
ball.x, | |
ball.y, | |
ball.radius | |
); | |
gradient.addColorStop(0, '#FFFFFF'); | |
gradient.addColorStop(1, '#00B0FF'); | |
ctx.fillStyle = gradient; | |
ctx.fill(); | |
ctx.closePath(); | |
// Add shine to ball | |
ctx.beginPath(); | |
ctx.arc(ball.x - ball.radius / 3, ball.y - ball.radius / 3, ball.radius / 4, 0, Math.PI * 2); | |
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; | |
ctx.fill(); | |
} | |
// Draw bricks | |
function drawBricks() { | |
for (let c = 0; c < brickColumnCount; c++) { | |
for (let r = 0; r < brickRowCount; r++) { | |
if (bricks[c][r].status === 1) { | |
const brick = bricks[c][r]; | |
// Draw brick with shadow | |
ctx.shadowColor = 'rgba(0, 0, 0, 0.3)'; | |
ctx.shadowBlur = 5; | |
ctx.shadowOffsetX = 2; | |
ctx.shadowOffsetY = 2; | |
ctx.beginPath(); | |
ctx.rect(brick.x, brick.y, brickWidth, brickHeight); | |
ctx.fillStyle = brick.color; | |
ctx.fill(); | |
// Reset shadow | |
ctx.shadowColor = 'transparent'; | |
// Add highlight to brick | |
ctx.beginPath(); | |
ctx.moveTo(brick.x, brick.y); | |
ctx.lineTo(brick.x + brickWidth, brick.y); | |
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; | |
ctx.lineWidth = 2; | |
ctx.stroke(); | |
// Add "200K" text to some bricks | |
if (Math.random() > 0.7) { | |
ctx.font = 'bold 10px Arial'; | |
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)'; | |
ctx.fillText('200K', brick.x + brickWidth/2 - 15, brick.y + brickHeight/2 + 3); | |
} | |
// Animation when hit | |
if (brick.hit) { | |
ctx.beginPath(); | |
ctx.rect(brick.x + 2, brick.y + 2, brickWidth - 4, brickHeight - 4); | |
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)'; | |
ctx.fill(); | |
brick.hit = false; | |
} | |
} | |
} | |
} | |
} | |
// Collision detection | |
function collisionDetection() { | |
for (let c = 0; c < brickColumnCount; c++) { | |
for (let r = 0; r < brickRowCount; r++) { | |
const brick = bricks[c][r]; | |
if (brick.status === 1) { | |
if ( | |
ball.x + ball.radius > brick.x && | |
ball.x - ball.radius < brick.x + brickWidth && | |
ball.y + ball.radius > brick.y && | |
ball.y - ball.radius < brick.y + brickHeight | |
) { | |
brick.hit = true; | |
ball.dy = -ball.dy; | |
brick.status = 0; | |
score += 10; | |
scoreDisplay.textContent = score; | |
createParticles(brick.x + brickWidth/2, brick.y + brickHeight/2, brick.color); | |
// Check if all bricks are cleared | |
if (checkLevelComplete()) { | |
levelComplete(); | |
} | |
} | |
} | |
} | |
} | |
} | |
// Check if level is complete | |
function checkLevelComplete() { | |
for (let c = 0; c < brickColumnCount; c++) { | |
for (let r = 0; r < brickRowCount; r++) { | |
if (bricks[c][r].status === 1) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
// Level complete | |
function levelComplete() { | |
level++; | |
levelDisplay.textContent = level; | |
// Increase difficulty | |
ball.speed += 0.5; | |
ball.dx = ball.dx > 0 ? ball.speed : -ball.speed; | |
ball.dy = -ball.speed; | |
// Reset ball and paddle | |
ball.x = canvas.width / 2; | |
ball.y = canvas.height - 30; | |
paddle.x = canvas.width / 2 - paddle.width / 2; | |
// Create new bricks | |
setTimeout(() => { | |
initBricks(); | |
}, 1000); | |
} | |
// Create particles when brick is hit | |
function createParticles(x, y, color) { | |
const particleCount = 8; | |
for (let i = 0; i < particleCount; i++) { | |
const particle = document.createElement('div'); | |
particle.className = 'confetti absolute'; | |
particle.style.left = `${x}px`; | |
particle.style.top = `${y}px`; | |
particle.style.backgroundColor = color; | |
particle.style.width = `${Math.random() * 8 + 4}px`; | |
particle.style.height = particle.style.width; | |
particle.style.borderRadius = '50%'; | |
document.body.appendChild(particle); | |
const angle = Math.random() * Math.PI * 2; | |
const velocity = Math.random() * 5 + 2; | |
const xVelocity = Math.cos(angle) * velocity; | |
const yVelocity = Math.sin(angle) * velocity; | |
let opacity = 1; | |
const fadeInterval = setInterval(() => { | |
opacity -= 0.05; | |
particle.style.opacity = opacity; | |
if (opacity <= 0) { | |
clearInterval(fadeInterval); | |
particle.remove(); | |
} | |
}, 30); | |
let posX = x; | |
let posY = y; | |
const moveInterval = setInterval(() => { | |
posX += xVelocity; | |
posY += yVelocity; | |
yVelocity += 0.1; // gravity | |
particle.style.left = `${posX}px`; | |
particle.style.top = `${posY}px`; | |
if (opacity <= 0) { | |
clearInterval(moveInterval); | |
} | |
}, 30); | |
} | |
} | |
// Create celebration confetti | |
function createConfetti() { | |
const colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff']; | |
const count = 150; | |
for (let i = 0; i < count; i++) { | |
const confetti = document.createElement('div'); | |
confetti.className = 'confetti absolute'; | |
confetti.style.left = `${Math.random() * window.innerWidth}px`; | |
confetti.style.top = `${-10}px`; | |
confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; | |
confetti.style.width = `${Math.random() * 10 + 5}px`; | |
confetti.style.height = `${Math.random() * 10 + 5}px`; | |
confetti.style.borderRadius = Math.random() > 0.5 ? '50%' : '0'; | |
confetti.style.transform = `rotate(${Math.random() * 360}deg)`; | |
document.body.appendChild(confetti); | |
const animationDuration = Math.random() * 3 + 2; | |
confetti.style.animation = `fall ${animationDuration}s linear forwards`; | |
// Add animation | |
const keyframes = ` | |
@keyframes fall { | |
to { | |
transform: translateY(${window.innerHeight + 10}px) rotate(${Math.random() * 360}deg); | |
opacity: 0; | |
} | |
} | |
`; | |
const styleEl = document.createElement('style'); | |
styleEl.innerHTML = keyframes; | |
document.head.appendChild(styleEl); | |
// Remove after animation | |
setTimeout(() => { | |
confetti.remove(); | |
styleEl.remove(); | |
}, animationDuration * 1000); | |
} | |
} | |
// Ball movement | |
function moveBall() { | |
// Wall collision (left/right) | |
if (ball.x + ball.dx > canvas.width - ball.radius || ball.x + ball.dx < ball.radius) { | |
ball.dx = -ball.dx; | |
} | |
// Wall collision (top) | |
if (ball.y + ball.dy < ball.radius) { | |
ball.dy = -ball.dy; | |
} | |
// Paddle collision | |
if ( | |
ball.y + ball.dy > canvas.height - ball.radius - paddle.height && | |
ball.x > paddle.x && | |
ball.x < paddle.x + paddle.width | |
) { | |
// Calculate bounce angle based on where ball hits paddle | |
const hitPosition = (ball.x - (paddle.x + paddle.width / 2)) / (paddle.width / 2); | |
ball.dx = hitPosition * 5; | |
ball.dy = -Math.abs(ball.dy); | |
// Add effect to paddle | |
const gradient = ctx.createLinearGradient(paddle.x, 0, paddle.x + paddle.width, 0); | |
gradient.addColorStop(0, '#FF4081'); | |
gradient.addColorStop(1, '#7C4DFF'); | |
ctx.fillStyle = gradient; | |
} | |
// Bottom wall (lose life) | |
if (ball.y + ball.dy > canvas.height - ball.radius) { | |
if (lives > 0) { | |
lives--; | |
livesDisplay.textContent = lives; | |
// Reset ball and paddle | |
ball.x = canvas.width / 2; | |
ball.y = canvas.height - 30; | |
ball.dx = 4; | |
ball.dy = -4; | |
paddle.x = canvas.width / 2 - paddle.width / 2; | |
// Flash screen red | |
document.body.style.backgroundColor = '#ff0000'; | |
setTimeout(() => { | |
document.body.style.backgroundColor = ''; | |
}, 100); | |
} else { | |
gameOver(false); | |
} | |
} | |
ball.x += ball.dx; | |
ball.y += ball.dy; | |
} | |
// Paddle movement | |
function movePaddle() { | |
if (paddle.isMoving) { | |
paddle.x += paddle.direction * paddle.speed; | |
// Keep paddle within canvas | |
if (paddle.x < 0) { | |
paddle.x = 0; | |
} else if (paddle.x + paddle.width > canvas.width) { | |
paddle.x = canvas.width - paddle.width; | |
} | |
} | |
} | |
// Draw game | |
function draw() { | |
// Clear canvas | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
// Draw elements | |
drawBricks(); | |
drawPaddle(); | |
drawBall(); | |
// Collision detection | |
collisionDetection(); | |
// Move elements | |
moveBall(); | |
movePaddle(); | |
// Continue animation if game is running | |
if (gameRunning) { | |
requestAnimationFrame(draw); | |
} | |
} | |
// Start game | |
function startGame() { | |
lives = 3; | |
score = 0; | |
level = 1; | |
livesDisplay.textContent = lives; | |
scoreDisplay.textContent = score; | |
levelDisplay.textContent = level; | |
initBricks(); | |
gameRunning = true; | |
startScreen.classList.add('hidden'); | |
gameOverScreen.classList.add('hidden'); | |
// Reset ball and paddle | |
ball.x = canvas.width / 2; | |
ball.y = canvas.height - 30; | |
ball.dx = 4; | |
ball.dy = -4; | |
ball.speed = 4; | |
paddle.x = canvas.width / 2 - paddle.width / 2; | |
draw(); | |
} | |
// Game over | |
function gameOver(win) { | |
gameRunning = false; | |
if (win) { | |
resultTitle.textContent = "Félicitations !"; | |
resultMessage.textContent = "Vous avez cassé toutes les briques des 200K abonnés !"; | |
createConfetti(); | |
} else { | |
resultTitle.textContent = "Game Over"; | |
resultMessage.textContent = "Vous avez perdu toutes vos vies. Essayez encore !"; | |
} | |
gameOverScreen.classList.remove('hidden'); | |
} | |
// Event listeners | |
startButton.addEventListener('click', startGame); | |
restartButton.addEventListener('click', startGame); | |
shareButton.addEventListener('click', () => { | |
if (navigator.share) { | |
navigator.share({ | |
title: '200K Brick Breaker', | |
text: `J'ai marqué ${score} points dans le jeu Brick Breaker 200K !`, | |
url: window.location.href | |
}).catch(console.error); | |
} else { | |
alert(`Partagez votre score de ${score} points sur les réseaux sociaux !`); | |
} | |
}); | |
// Keyboard controls | |
document.addEventListener('keydown', (e) => { | |
if (e.key === 'Right' || e.key === 'ArrowRight') { | |
paddle.isMoving = true; | |
paddle.direction = 1; | |
} else if (e.key === 'Left' || e.key === 'ArrowLeft') { | |
paddle.isMoving = true; | |
paddle.direction = -1; | |
} else if (e.key === ' ' && !gameRunning && !startScreen.classList.contains('hidden')) { | |
startGame(); | |
} | |
}); | |
document.addEventListener('keyup', (e) => { | |
if (e.key === 'Right' || e.key === 'ArrowRight' || e.key === 'Left' || e.key === 'ArrowLeft') { | |
paddle.isMoving = false; | |
} | |
}); | |
// Mouse/touch controls | |
canvas.addEventListener('mousemove', (e) => { | |
if (!gameRunning) return; | |
const relativeX = e.clientX - canvas.getBoundingClientRect().left; | |
if (relativeX > 0 && relativeX < canvas.width) { | |
paddle.x = relativeX - paddle.width / 2; | |
// Keep paddle within canvas | |
if (paddle.x < 0) { | |
paddle.x = 0; | |
} else if (paddle.x + paddle.width > canvas.width) { | |
paddle.x = canvas.width - paddle.width; | |
} | |
} | |
}); | |
// Touch controls for mobile | |
canvas.addEventListener('touchmove', (e) => { | |
if (!gameRunning) return; | |
e.preventDefault(); | |
const touch = e.touches[0]; | |
const relativeX = touch.clientX - canvas.getBoundingClientRect().left; | |
if (relativeX > 0 && relativeX < canvas.width) { | |
paddle.x = relativeX - paddle.width / 2; | |
// Keep paddle within canvas | |
if (paddle.x < 0) { | |
paddle.x = 0; | |
} else if (paddle.x + paddle.width > canvas.width) { | |
paddle.x = canvas.width - paddle.width; | |
} | |
} | |
}); | |
// Initialize game | |
initBricks(); | |
}); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=LudoSLN/ludo-salenne" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |