diff --git a/game.js b/game.js index ba75f31..f046345 100644 --- a/game.js +++ b/game.js @@ -1097,6 +1097,7 @@ function saveScore() { const topScores = scores.slice(0, 10); localStorage.setItem('pacmanScores', JSON.stringify(topScores)); updateLeaderboard(); + updateBestScore(); // Mettre à jour le meilleur score dans le menu } } @@ -1252,6 +1253,177 @@ function animateScore() { } animateScore(); +// === FANTOMES ANIMES EN ARRIERE-PLAN DU MENU === +const menuCanvas = document.getElementById('menuBackgroundCanvas'); +const menuCtx = menuCanvas.getContext('2d'); + +// Ajuster la taille du canvas +function resizeMenuCanvas() { + menuCanvas.width = window.innerWidth; + menuCanvas.height = window.innerHeight; +} +resizeMenuCanvas(); +window.addEventListener('resize', resizeMenuCanvas); + +// Classe pour les fantômes du menu +class MenuGhost { + constructor() { + this.x = Math.random() * menuCanvas.width; + this.y = Math.random() * menuCanvas.height; + this.speedX = (Math.random() - 0.5) * 2; + this.speedY = (Math.random() - 0.5) * 2; + this.size = 30 + Math.random() * 20; + this.color = ['#ff0000', '#ff00ff', '#00ffff', '#ffa500'][Math.floor(Math.random() * 4)]; + this.animation = Math.random() * Math.PI * 2; + } + + update() { + this.x += this.speedX; + this.y += this.speedY; + this.animation += 0.05; + + // Rebondir sur les bords + if (this.x < 0 || this.x > menuCanvas.width) { + this.speedX *= -1; + } + if (this.y < 0 || this.y > menuCanvas.height) { + this.speedY *= -1; + } + + // Garder dans les limites + this.x = Math.max(0, Math.min(menuCanvas.width, this.x)); + this.y = Math.max(0, Math.min(menuCanvas.height, this.y)); + } + + draw() { + menuCtx.save(); + menuCtx.translate(this.x, this.y); + + const size = this.size; + const waveOffset = Math.sin(this.animation) * 2; + + // Corps du fantôme + menuCtx.fillStyle = this.color; + menuCtx.strokeStyle = '#000000'; + menuCtx.lineWidth = 2; + + // Tête (demi-cercle) + menuCtx.beginPath(); + menuCtx.arc(0, -size * 0.3, size * 0.5, Math.PI, 0, false); + menuCtx.fill(); + menuCtx.stroke(); + + // Corps (rectangle) + menuCtx.fillRect(-size * 0.5, -size * 0.3, size * 1.0, size * 0.7); + menuCtx.strokeRect(-size * 0.5, -size * 0.3, size * 1.0, size * 0.7); + + // Jambes ondulées + const waveHeight = size * 0.15; + const waveWidth = size * 0.2; + menuCtx.beginPath(); + menuCtx.moveTo(-size * 0.5, size * 0.4); + for (let i = 0; i < 5; i++) { + const x = -size * 0.5 + i * waveWidth; + const y = size * 0.4 + (i % 2 === 0 ? 0 : waveHeight) + waveOffset; + menuCtx.lineTo(x, y); + } + menuCtx.lineTo(size * 0.5, size * 0.4); + menuCtx.lineTo(size * 0.5, size * 0.7); + menuCtx.lineTo(-size * 0.5, size * 0.7); + menuCtx.closePath(); + menuCtx.fill(); + menuCtx.stroke(); + + // Yeux + menuCtx.fillStyle = '#ffffff'; + menuCtx.beginPath(); + menuCtx.arc(-size * 0.2, -size * 0.1, size * 0.12, 0, Math.PI * 2); + menuCtx.arc(size * 0.2, -size * 0.1, size * 0.12, 0, Math.PI * 2); + menuCtx.fill(); + + menuCtx.fillStyle = '#000000'; + menuCtx.beginPath(); + menuCtx.arc(-size * 0.2, -size * 0.1, size * 0.06, 0, Math.PI * 2); + menuCtx.arc(size * 0.2, -size * 0.1, size * 0.06, 0, Math.PI * 2); + menuCtx.fill(); + + menuCtx.restore(); + } +} + +// Créer plusieurs fantômes +const menuGhosts = []; +const numGhosts = 6; + +for (let i = 0; i < numGhosts; i++) { + menuGhosts.push(new MenuGhost()); +} + +// Animation du menu +let menuAnimationRunning = false; +let menuAnimationFrame = null; + +function animateMenu() { + if (!menuAnimationRunning) return; + + // Effacer le canvas avec un effet de traînée + menuCtx.fillStyle = 'rgba(10, 10, 10, 0.1)'; + menuCtx.fillRect(0, 0, menuCanvas.width, menuCanvas.height); + + // Mettre à jour et dessiner les fantômes + menuGhosts.forEach(ghost => { + ghost.update(); + ghost.draw(); + }); + + menuAnimationFrame = requestAnimationFrame(animateMenu); +} + +// Démarrer l'animation seulement si le menu est visible +function startMenuAnimation() { + if (!menuAnimationRunning && mainMenu && mainMenu.style.display !== 'none') { + menuAnimationRunning = true; + animateMenu(); + } +} + +function stopMenuAnimation() { + menuAnimationRunning = false; + if (menuAnimationFrame) { + cancelAnimationFrame(menuAnimationFrame); + } +} + +// Démarrer l'animation au chargement si le menu est visible +// Attendre que le DOM soit complètement chargé +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', () => { + if (mainMenu && mainMenu.style.display !== 'none') { + startMenuAnimation(); + } + }); +} else { + // DOM déjà chargé + if (mainMenu && mainMenu.style.display !== 'none') { + startMenuAnimation(); + } +} + +// Observer les changements de visibilité du menu +if (mainMenu) { + const menuObserver = new MutationObserver(() => { + if (mainMenu.style.display !== 'none') { + if (!menuAnimationRunning) { + startMenuAnimation(); + } + } else { + stopMenuAnimation(); + } + }); + + menuObserver.observe(mainMenu, { attributes: true, attributeFilter: ['style'] }); +} + // === GESTION DU MENU === // Afficher le jeu playBtn.addEventListener('click', () => { @@ -1269,6 +1441,8 @@ backToMenuBtn.addEventListener('click', () => { gameWrapper.style.display = 'none'; mainMenu.style.display = 'flex'; gameRunning = false; + updateBestScore(); // Mettre à jour le meilleur score + startMenuAnimation(); // Redémarrer l'animation des fantômes } }); @@ -1335,6 +1509,21 @@ function updateMenuLeaderboard() { }); } +// Fonction pour mettre à jour le meilleur score dans le menu +function updateBestScore() { + const scores = getScores(); + const bestScoreElement = document.getElementById('bestScoreValue'); + + if (scores.length > 0) { + const bestScore = scores[0].score; + const bestLevel = scores[0].level || 1; + bestScoreElement.textContent = `${bestScore} (Niv. ${bestLevel})`; + } else { + bestScoreElement.textContent = '0'; + } +} + // Initialiser seulement le menu au chargement updateMenuLeaderboard(); +updateBestScore(); diff --git a/index.html b/index.html index 6db5640..2ec770e 100644 --- a/index.html +++ b/index.html @@ -9,11 +9,21 @@ diff --git a/style.css b/style.css index d4417f1..134a0e6 100644 --- a/style.css +++ b/style.css @@ -142,27 +142,92 @@ body::after { width: 100%; height: 100%; z-index: 1000; + overflow: hidden; +} + +/* === CANVAS ARRIERE-PLAN MENU === */ +#menuBackgroundCanvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; + opacity: 0.3; + pointer-events: none; } .menu-container { + position: relative; + z-index: 2; text-align: center; - background: rgba(0, 0, 0, 0.8); + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); padding: 50px 40px; border-radius: 20px; - border: 3px solid rgba(255, 215, 0, 0.4); + border: 1px solid rgba(255, 215, 0, 0.3); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.8), 0 0 50px rgba(255, 0, 0, 0.2), inset 0 0 30px rgba(255, 215, 0, 0.05); + animation: menuFadeIn 0.8s ease-out; +} + +@keyframes menuFadeIn { + from { + opacity: 0; + transform: scale(0.9) translateY(-20px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } } .menu-container h1 { font-size: 3em; - margin-bottom: 40px; + margin-bottom: 20px; letter-spacing: 5px; animation: neonFlicker 3s infinite, rainbow 8s linear infinite; } +.menu-subtitle { + font-size: 0.6em; + color: #ffd700; + margin-bottom: 25px; + text-shadow: 0 0 10px rgba(255, 215, 0, 0.5); + animation: subtitleGlow 2s ease-in-out infinite; + line-height: 1.6; +} + +@keyframes subtitleGlow { + 0%, 100% { opacity: 0.7; } + 50% { opacity: 1; } +} + +.best-score-display { + font-size: 0.7em; + color: #ffd700; + margin-bottom: 30px; + padding: 12px 25px; + background: rgba(255, 215, 0, 0.1); + border: 1px solid rgba(255, 215, 0, 0.3); + border-radius: 10px; + display: inline-block; +} + +.best-score-label { + margin-right: 10px; +} + +.best-score-value { + color: #00ff00; + font-size: 1.3em; + font-weight: bold; + text-shadow: 0 0 10px rgba(0, 255, 0, 0.5); +} + .menu-buttons { display: flex; flex-direction: column; @@ -183,12 +248,34 @@ body::after { transition: all 0.3s; box-shadow: 0 5px 15px rgba(255, 215, 0, 0.4); min-width: 250px; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + animation: buttonPulse 2s ease-in-out infinite; +} + +@keyframes buttonPulse { + 0%, 100% { + box-shadow: 0 5px 15px rgba(255, 215, 0, 0.4); + } + 50% { + box-shadow: 0 5px 25px rgba(255, 215, 0, 0.7); + } +} + +.btn-icon { + font-size: 0.9em; } .menu-btn:hover { background: linear-gradient(180deg, #ffed4e 0%, #ffa500 100%); transform: translateY(-3px); - box-shadow: 0 8px 20px rgba(255, 215, 0, 0.6); + box-shadow: + 0 8px 20px rgba(255, 215, 0, 0.6), + 0 0 30px rgba(255, 215, 0, 0.4); + text-shadow: 0 0 10px rgba(0, 0, 0, 0.5); + animation: none; } .menu-btn:active { @@ -806,6 +893,21 @@ footer { font-size: 2em; } + .menu-subtitle { + font-size: 0.5em; + margin-bottom: 20px; + } + + .best-score-display { + font-size: 0.6em; + padding: 10px 15px; + margin-bottom: 25px; + } + + .best-score-value { + font-size: 1.1em; + } + .menu-btn { min-width: 200px; padding: 15px 30px;