texture triangle ameliorer

This commit is contained in:
2025-12-02 19:56:46 +01:00
parent 5091fc3d6e
commit 844c64c7b6
3 changed files with 256 additions and 14 deletions

180
game.js
View File

@ -38,6 +38,7 @@ const closeCustomizeBtn = document.getElementById('closeCustomizeBtn');
const saveCustomizeBtn = document.getElementById('saveCustomizeBtn'); const saveCustomizeBtn = document.getElementById('saveCustomizeBtn');
const playerPreviewCanvas = document.getElementById('playerPreviewCanvas'); const playerPreviewCanvas = document.getElementById('playerPreviewCanvas');
const colorOptions = document.querySelectorAll('.color-option'); const colorOptions = document.querySelectorAll('.color-option');
const shapeOptions = document.querySelectorAll('.shape-option');
// Fonction pour vérifier si on est en mode plein écran // Fonction pour vérifier si on est en mode plein écran
function isFullscreen() { function isFullscreen() {
@ -50,6 +51,7 @@ let gameOverUsername = null;
// Personnalisation du joueur // Personnalisation du joueur
let playerColor = localStorage.getItem('playerColor') || 'rainbow'; let playerColor = localStorage.getItem('playerColor') || 'rainbow';
let playerShape = localStorage.getItem('playerShape') || 'round';
const CELL_SIZE = 25; const CELL_SIZE = 25;
const COLS = 30; const COLS = 30;
@ -253,7 +255,7 @@ let traps = [];
let specialZones = []; let specialZones = [];
class Pacman { class Pacman {
constructor(color = null) { constructor(color = null, shape = null) {
this.x = 14; this.x = 14;
this.y = 23; this.y = 23;
this.direction = 0; this.direction = 0;
@ -266,6 +268,7 @@ class Pacman {
this.pixelY = this.y * CELL_SIZE + CELL_SIZE / 2; this.pixelY = this.y * CELL_SIZE + CELL_SIZE / 2;
this.colorAnimation = 0; this.colorAnimation = 0;
this.color = color || playerColor; this.color = color || playerColor;
this.shape = shape || playerShape;
} }
update() { update() {
@ -471,9 +474,11 @@ class Pacman {
ctx.rotate(rotation[this.direction]); ctx.rotate(rotation[this.direction]);
// Utiliser la couleur personnalisée // Utiliser la couleur personnalisée
let baseFillColor;
if (this.color === 'rainbow') { if (this.color === 'rainbow') {
const hue = (this.colorAnimation * 180 / Math.PI) % 360; const hue = (this.colorAnimation * 180 / Math.PI) % 360;
ctx.fillStyle = `hsl(${hue}, 100%, 50%)`; baseFillColor = `hsl(${hue}, 100%, 50%)`;
ctx.fillStyle = baseFillColor;
} else { } else {
const colorMap = { const colorMap = {
'yellow': '#ffd700', 'yellow': '#ffd700',
@ -484,19 +489,77 @@ class Pacman {
'orange': '#ff8844', 'orange': '#ff8844',
'pink': '#ff44aa' 'pink': '#ff44aa'
}; };
ctx.fillStyle = colorMap[this.color] || '#ffd700'; baseFillColor = colorMap[this.color] || '#ffd700';
ctx.fillStyle = baseFillColor;
} }
const size = CELL_SIZE * 0.4;
ctx.beginPath(); ctx.beginPath();
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) { if (this.mouthOpen) {
ctx.arc(0, 0, CELL_SIZE * 0.4, 0.2, Math.PI * 2 - 0.2); // 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 { } else {
ctx.arc(0, 0, CELL_SIZE * 0.4, 0, Math.PI * 2); // 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 {
// 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.lineTo(0, 0);
ctx.fill(); ctx.fill();
}
ctx.restore(); ctx.restore();
} }
@ -2487,6 +2550,7 @@ if (rulesModal) {
// === GESTION DU MODAL DE PERSONNALISATION === // === GESTION DU MODAL DE PERSONNALISATION ===
let selectedColor = playerColor; let selectedColor = playerColor;
let selectedShape = playerShape;
// Ouvrir le modal de personnalisation // Ouvrir le modal de personnalisation
if (customizeBtn) { if (customizeBtn) {
@ -2494,7 +2558,9 @@ if (customizeBtn) {
if (customizeModal) { if (customizeModal) {
customizeModal.style.display = 'flex'; customizeModal.style.display = 'flex';
selectedColor = playerColor; selectedColor = playerColor;
selectedShape = playerShape;
updateColorSelection(); updateColorSelection();
updateShapeSelection();
updatePlayerPreview(); updatePlayerPreview();
startPreviewAnimation(); 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 // Mettre à jour la sélection visuelle
function updateColorSelection() { function updateColorSelection() {
if (colorOptions) { 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 // Prévisualisation du joueur
let previewAnimationId = null; let previewAnimationId = null;
function startPreviewAnimation() { function startPreviewAnimation() {
@ -2589,14 +2678,86 @@ function startPreviewAnimation() {
mouthOpen = !mouthOpen; mouthOpen = !mouthOpen;
} }
const size = 40;
ctx.beginPath();
if (selectedShape === 'triangle') {
const triangleSize = size * 1.5; // Plus grand pour une meilleure visibilité
// Dessiner le triangle avec contour et yeux
ctx.beginPath(); ctx.beginPath();
const radius = 40;
if (mouthOpen) { if (mouthOpen) {
ctx.arc(0, 0, radius, 0.2, Math.PI * 2 - 0.2); // 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 { } else {
ctx.arc(0, 0, radius, 0, Math.PI * 2); // 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 {
// 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.fill();
ctx.restore(); ctx.restore();
@ -2622,11 +2783,14 @@ function updatePlayerPreview() {
if (saveCustomizeBtn) { if (saveCustomizeBtn) {
saveCustomizeBtn.addEventListener('click', () => { saveCustomizeBtn.addEventListener('click', () => {
playerColor = selectedColor; playerColor = selectedColor;
playerShape = selectedShape;
localStorage.setItem('playerColor', playerColor); localStorage.setItem('playerColor', playerColor);
localStorage.setItem('playerShape', playerShape);
// Mettre à jour le joueur actuel si le jeu est en cours // Mettre à jour le joueur actuel si le jeu est en cours
if (pacman) { if (pacman) {
pacman.color = playerColor; pacman.color = playerColor;
pacman.shape = playerShape;
} }
// Fermer le modal // Fermer le modal

View File

@ -276,6 +276,19 @@
</div> </div>
</div> </div>
</div> </div>
<div class="customize-section">
<h3>Forme du joueur</h3>
<div class="shape-options">
<div class="shape-option active" data-shape="round" data-name="Rond">
<div class="shape-preview round-preview"></div>
<span>Rond (Classique)</span>
</div>
<div class="shape-option" data-shape="triangle" data-name="Triangle">
<div class="shape-preview triangle-preview"></div>
<span>Triangle</span>
</div>
</div>
</div>
<div class="customize-preview"> <div class="customize-preview">
<h3>Aperçu</h3> <h3>Aperçu</h3>
<canvas id="playerPreviewCanvas" width="200" height="200"></canvas> <canvas id="playerPreviewCanvas" width="200" height="200"></canvas>

View File

@ -1479,3 +1479,68 @@ footer {
.save-customize-btn:active { .save-customize-btn:active {
transform: translateY(0) scale(0.98); 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;
}