amelior interface menu

This commit is contained in:
2025-12-01 22:34:05 +01:00
parent f311d3f103
commit 502a462ec5
3 changed files with 307 additions and 6 deletions

189
game.js
View File

@ -1097,6 +1097,7 @@ function saveScore() {
const topScores = scores.slice(0, 10); const topScores = scores.slice(0, 10);
localStorage.setItem('pacmanScores', JSON.stringify(topScores)); localStorage.setItem('pacmanScores', JSON.stringify(topScores));
updateLeaderboard(); updateLeaderboard();
updateBestScore(); // Mettre à jour le meilleur score dans le menu
} }
} }
@ -1252,6 +1253,177 @@ function animateScore() {
} }
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 === // === GESTION DU MENU ===
// Afficher le jeu // Afficher le jeu
playBtn.addEventListener('click', () => { playBtn.addEventListener('click', () => {
@ -1269,6 +1441,8 @@ backToMenuBtn.addEventListener('click', () => {
gameWrapper.style.display = 'none'; gameWrapper.style.display = 'none';
mainMenu.style.display = 'flex'; mainMenu.style.display = 'flex';
gameRunning = false; 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 // Initialiser seulement le menu au chargement
updateMenuLeaderboard(); updateMenuLeaderboard();
updateBestScore();

View File

@ -9,11 +9,21 @@
<body> <body>
<!-- MENU PRINCIPAL --> <!-- MENU PRINCIPAL -->
<div class="main-menu" id="mainMenu"> <div class="main-menu" id="mainMenu">
<canvas id="menuBackgroundCanvas"></canvas>
<div class="menu-container"> <div class="menu-container">
<h1>OULVIC</h1> <h1>OULVIC</h1>
<p class="menu-subtitle">Évitez les fantômes et collectez les pastilles !</p>
<div class="best-score-display" id="bestScoreDisplay">
<span class="best-score-label">Meilleur Score:</span>
<span class="best-score-value" id="bestScoreValue">0</span>
</div>
<div class="menu-buttons"> <div class="menu-buttons">
<button class="menu-btn" id="playBtn">JOUER</button> <button class="menu-btn" id="playBtn">
<button class="menu-btn" id="scoresBtn">CLASSEMENT</button> <span class="btn-icon"></span> JOUER
</button>
<button class="menu-btn" id="scoresBtn">
<span class="btn-icon">🏆</span> CLASSEMENT
</button>
</div> </div>
</div> </div>
</div> </div>

110
style.css
View File

@ -142,27 +142,92 @@ body::after {
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: 1000; 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 { .menu-container {
position: relative;
z-index: 2;
text-align: center; 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; padding: 50px 40px;
border-radius: 20px; border-radius: 20px;
border: 3px solid rgba(255, 215, 0, 0.4); border: 1px solid rgba(255, 215, 0, 0.3);
box-shadow: box-shadow:
0 10px 30px rgba(0, 0, 0, 0.8), 0 10px 30px rgba(0, 0, 0, 0.8),
0 0 50px rgba(255, 0, 0, 0.2), 0 0 50px rgba(255, 0, 0, 0.2),
inset 0 0 30px rgba(255, 215, 0, 0.05); 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 { .menu-container h1 {
font-size: 3em; font-size: 3em;
margin-bottom: 40px; margin-bottom: 20px;
letter-spacing: 5px; letter-spacing: 5px;
animation: neonFlicker 3s infinite, rainbow 8s linear infinite; 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 { .menu-buttons {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -183,12 +248,34 @@ body::after {
transition: all 0.3s; transition: all 0.3s;
box-shadow: 0 5px 15px rgba(255, 215, 0, 0.4); box-shadow: 0 5px 15px rgba(255, 215, 0, 0.4);
min-width: 250px; 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 { .menu-btn:hover {
background: linear-gradient(180deg, #ffed4e 0%, #ffa500 100%); background: linear-gradient(180deg, #ffed4e 0%, #ffa500 100%);
transform: translateY(-3px); 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 { .menu-btn:active {
@ -806,6 +893,21 @@ footer {
font-size: 2em; 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 { .menu-btn {
min-width: 200px; min-width: 200px;
padding: 15px 30px; padding: 15px 30px;