diff --git a/game.js b/game.js index 18a112f..0dbba0e 100644 --- a/game.js +++ b/game.js @@ -38,6 +38,7 @@ const closeCustomizeBtn = document.getElementById('closeCustomizeBtn'); const saveCustomizeBtn = document.getElementById('saveCustomizeBtn'); const playerPreviewCanvas = document.getElementById('playerPreviewCanvas'); const colorOptions = document.querySelectorAll('.color-option'); +const shapeOptions = document.querySelectorAll('.shape-option'); // Fonction pour vérifier si on est en mode plein écran function isFullscreen() { @@ -50,6 +51,7 @@ let gameOverUsername = null; // Personnalisation du joueur let playerColor = localStorage.getItem('playerColor') || 'rainbow'; +let playerShape = localStorage.getItem('playerShape') || 'round'; const CELL_SIZE = 25; const COLS = 30; @@ -253,7 +255,7 @@ let traps = []; let specialZones = []; class Pacman { - constructor(color = null) { + constructor(color = null, shape = null) { this.x = 14; this.y = 23; this.direction = 0; @@ -266,6 +268,7 @@ class Pacman { this.pixelY = this.y * CELL_SIZE + CELL_SIZE / 2; this.colorAnimation = 0; this.color = color || playerColor; + this.shape = shape || playerShape; } update() { @@ -471,9 +474,11 @@ class Pacman { ctx.rotate(rotation[this.direction]); // Utiliser la couleur personnalisée + let baseFillColor; if (this.color === 'rainbow') { const hue = (this.colorAnimation * 180 / Math.PI) % 360; - ctx.fillStyle = `hsl(${hue}, 100%, 50%)`; + baseFillColor = `hsl(${hue}, 100%, 50%)`; + ctx.fillStyle = baseFillColor; } else { const colorMap = { 'yellow': '#ffd700', @@ -484,20 +489,78 @@ class Pacman { 'orange': '#ff8844', 'pink': '#ff44aa' }; - ctx.fillStyle = colorMap[this.color] || '#ffd700'; + baseFillColor = colorMap[this.color] || '#ffd700'; + ctx.fillStyle = baseFillColor; } + const size = CELL_SIZE * 0.4; + ctx.beginPath(); - if (this.mouthOpen) { - ctx.arc(0, 0, CELL_SIZE * 0.4, 0.2, Math.PI * 2 - 0.2); + if (this.shape === 'triangle') { + const triangleSize = size * 1.5; // Plus grand pour une meilleure visibilité + + // Dessiner le triangle avec contour et yeux + ctx.beginPath(); + if (this.mouthOpen) { + // Triangle avec bouche ouverte - ouverture plus grande et visible + ctx.moveTo(0, -triangleSize * 0.9); + ctx.lineTo(-triangleSize * 0.85, triangleSize * 0.7); + ctx.lineTo(-triangleSize * 0.4, triangleSize * 0.4); + ctx.lineTo(0, triangleSize * 0.2); + ctx.lineTo(triangleSize * 0.4, triangleSize * 0.4); + ctx.lineTo(triangleSize * 0.85, triangleSize * 0.7); + ctx.closePath(); + } else { + // Triangle équilatéral complet + ctx.moveTo(0, -triangleSize); + ctx.lineTo(-triangleSize * 0.866, triangleSize * 0.5); // cos(30°) ≈ 0.866 + ctx.lineTo(triangleSize * 0.866, triangleSize * 0.5); + ctx.closePath(); + } + + // Remplir le triangle + ctx.fill(); + + // Contour noir épais pour plus de définition + ctx.strokeStyle = '#000000'; + ctx.lineWidth = 2.5; + ctx.stroke(); + + // Dessiner les yeux + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(-triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.12, 0, Math.PI * 2); + ctx.arc(triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.12, 0, Math.PI * 2); + ctx.fill(); + + // Pupilles + ctx.fillStyle = '#000000'; + ctx.beginPath(); + ctx.arc(-triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.06, 0, Math.PI * 2); + ctx.arc(triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.06, 0, Math.PI * 2); + ctx.fill(); + + // Reflets dans les yeux pour plus de vie + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(-triangleSize * 0.22, -triangleSize * 0.17, triangleSize * 0.03, 0, Math.PI * 2); + ctx.arc(triangleSize * 0.18, -triangleSize * 0.17, triangleSize * 0.03, 0, Math.PI * 2); + ctx.fill(); + + // Restaurer la couleur originale + ctx.fillStyle = baseFillColor; } else { - ctx.arc(0, 0, CELL_SIZE * 0.4, 0, Math.PI * 2); + // Forme ronde (par défaut) + if (this.mouthOpen) { + ctx.arc(0, 0, size, 0.2, Math.PI * 2 - 0.2); + } else { + ctx.arc(0, 0, size, 0, Math.PI * 2); + } + ctx.lineTo(0, 0); + ctx.fill(); } - ctx.lineTo(0, 0); - ctx.fill(); - ctx.restore(); } } @@ -2487,6 +2550,7 @@ if (rulesModal) { // === GESTION DU MODAL DE PERSONNALISATION === let selectedColor = playerColor; +let selectedShape = playerShape; // Ouvrir le modal de personnalisation if (customizeBtn) { @@ -2494,7 +2558,9 @@ if (customizeBtn) { if (customizeModal) { customizeModal.style.display = 'flex'; selectedColor = playerColor; + selectedShape = playerShape; updateColorSelection(); + updateShapeSelection(); updatePlayerPreview(); startPreviewAnimation(); } @@ -2532,6 +2598,17 @@ if (colorOptions) { }); } +// Gérer la sélection de forme +if (shapeOptions) { + shapeOptions.forEach(option => { + option.addEventListener('click', () => { + selectedShape = option.getAttribute('data-shape'); + updateShapeSelection(); + updatePlayerPreview(); + }); + }); +} + // Mettre à jour la sélection visuelle function updateColorSelection() { if (colorOptions) { @@ -2545,6 +2622,18 @@ function updateColorSelection() { } } +function updateShapeSelection() { + if (shapeOptions) { + shapeOptions.forEach(option => { + if (option.getAttribute('data-shape') === selectedShape) { + option.classList.add('active'); + } else { + option.classList.remove('active'); + } + }); + } +} + // Prévisualisation du joueur let previewAnimationId = null; function startPreviewAnimation() { @@ -2589,14 +2678,86 @@ function startPreviewAnimation() { mouthOpen = !mouthOpen; } + const size = 40; ctx.beginPath(); - const radius = 40; - if (mouthOpen) { - ctx.arc(0, 0, radius, 0.2, Math.PI * 2 - 0.2); + + if (selectedShape === 'triangle') { + const triangleSize = size * 1.5; // Plus grand pour une meilleure visibilité + + // Dessiner le triangle avec contour et yeux + ctx.beginPath(); + if (mouthOpen) { + // Triangle avec bouche ouverte + ctx.moveTo(0, -triangleSize * 0.9); + ctx.lineTo(-triangleSize * 0.85, triangleSize * 0.7); + ctx.lineTo(-triangleSize * 0.4, triangleSize * 0.4); + ctx.lineTo(0, triangleSize * 0.2); + ctx.lineTo(triangleSize * 0.4, triangleSize * 0.4); + ctx.lineTo(triangleSize * 0.85, triangleSize * 0.7); + ctx.closePath(); + } else { + // Triangle équilatéral complet + ctx.moveTo(0, -triangleSize); + ctx.lineTo(-triangleSize * 0.866, triangleSize * 0.5); + ctx.lineTo(triangleSize * 0.866, triangleSize * 0.5); + ctx.closePath(); + } + + // Remplir le triangle + ctx.fill(); + + // Contour noir épais + ctx.strokeStyle = '#000000'; + ctx.lineWidth = 2.5; + ctx.stroke(); + + // Dessiner les yeux + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(-triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.12, 0, Math.PI * 2); + ctx.arc(triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.12, 0, Math.PI * 2); + ctx.fill(); + + // Pupilles + ctx.fillStyle = '#000000'; + ctx.beginPath(); + ctx.arc(-triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.06, 0, Math.PI * 2); + ctx.arc(triangleSize * 0.2, -triangleSize * 0.15, triangleSize * 0.06, 0, Math.PI * 2); + ctx.fill(); + + // Reflets dans les yeux + ctx.fillStyle = '#ffffff'; + ctx.beginPath(); + ctx.arc(-triangleSize * 0.22, -triangleSize * 0.17, triangleSize * 0.03, 0, Math.PI * 2); + ctx.arc(triangleSize * 0.18, -triangleSize * 0.17, triangleSize * 0.03, 0, Math.PI * 2); + ctx.fill(); + + // Restaurer la couleur originale + if (selectedColor === 'rainbow') { + const hue = (angle * 180 / Math.PI) % 360; + ctx.fillStyle = `hsl(${hue}, 100%, 50%)`; + } else { + const colorMap = { + 'yellow': '#ffd700', + 'red': '#ff4444', + 'blue': '#4444ff', + 'green': '#44ff44', + 'purple': '#aa44ff', + 'orange': '#ff8844', + 'pink': '#ff44aa' + }; + ctx.fillStyle = colorMap[selectedColor] || '#ffd700'; + } } else { - ctx.arc(0, 0, radius, 0, Math.PI * 2); + // Dessiner un cercle + if (mouthOpen) { + ctx.arc(0, 0, size, 0.2, Math.PI * 2 - 0.2); + } else { + ctx.arc(0, 0, size, 0, Math.PI * 2); + } + ctx.lineTo(0, 0); } - ctx.lineTo(0, 0); + ctx.fill(); ctx.restore(); @@ -2622,11 +2783,14 @@ function updatePlayerPreview() { if (saveCustomizeBtn) { saveCustomizeBtn.addEventListener('click', () => { playerColor = selectedColor; + playerShape = selectedShape; localStorage.setItem('playerColor', playerColor); + localStorage.setItem('playerShape', playerShape); // Mettre à jour le joueur actuel si le jeu est en cours if (pacman) { pacman.color = playerColor; + pacman.shape = playerShape; } // Fermer le modal diff --git a/index.html b/index.html index 68e8a52..0b82c59 100644 --- a/index.html +++ b/index.html @@ -276,6 +276,19 @@ +
+

Forme du joueur

+
+
+
+ Rond (Classique) +
+
+
+ Triangle +
+
+

Aperçu

diff --git a/style.css b/style.css index bc5d8f4..86f72ee 100644 --- a/style.css +++ b/style.css @@ -1479,3 +1479,68 @@ footer { .save-customize-btn:active { transform: translateY(0) scale(0.98); } + +.shape-options { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 15px; + margin-top: 15px; +} + +.shape-option { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 15px; + background: rgba(255, 255, 255, 0.05); + border: 2px solid rgba(255, 215, 0, 0.3); + border-radius: 10px; + cursor: pointer; + transition: all 0.3s; +} + +.shape-option:hover { + background: rgba(255, 215, 0, 0.1); + border-color: #ffd700; + transform: scale(1.05); +} + +.shape-option.active { + background: rgba(255, 215, 0, 0.2); + border-color: #ffd700; + box-shadow: 0 0 15px rgba(255, 215, 0, 0.5); +} + +.shape-preview { + width: 60px; + height: 60px; + display: flex; + align-items: center; + justify-content: center; +} + +.round-preview { + width: 50px; + height: 50px; + border-radius: 50%; + background: #ffd700; + border: 3px solid #fff; + box-shadow: 0 0 10px rgba(255, 255, 255, 0.3); +} + +.triangle-preview { + width: 0; + height: 0; + border-left: 25px solid transparent; + border-right: 25px solid transparent; + border-bottom: 45px solid #ffd700; + border-top: none; + filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.3)); +} + +.shape-option span { + font-size: 0.7em; + color: #fff; + text-align: center; +}