texture zebre plus sourie menu

This commit is contained in:
2025-12-19 16:22:09 +01:00
parent 844c64c7b6
commit 1b474fcbca
4 changed files with 767 additions and 86 deletions

301
game.js
View File

@ -550,6 +550,124 @@ class Pacman {
// Restaurer la couleur originale
ctx.fillStyle = baseFillColor;
} else if (this.shape === 'zebre') {
// Dessiner un zèbre plus réaliste
const bodyWidth = size * 1.8;
const bodyHeight = size * 1.4;
ctx.save();
// Corps (ellipse allongée)
ctx.beginPath();
ctx.ellipse(0, size * 0.2, bodyWidth, bodyHeight, 0, 0, Math.PI * 2);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
ctx.stroke();
// Rayures noires horizontales sur le corps
ctx.fillStyle = '#000000';
const stripeCount = 8;
const stripeSpacing = (bodyHeight * 2) / stripeCount;
for (let i = 0; i < stripeCount; i++) {
if (i % 2 === 1) { // Alterner les rayures
const yPos = -bodyHeight + (i * stripeSpacing);
ctx.beginPath();
ctx.ellipse(0, yPos + size * 0.2, bodyWidth * 0.95, stripeSpacing * 0.5, 0, 0, Math.PI * 2);
ctx.fill();
}
}
// Tête (cercle légèrement plus petit au-dessus du corps)
const headSize = size * 0.9;
ctx.beginPath();
if (this.mouthOpen) {
ctx.arc(0, -bodyHeight - headSize * 0.2, headSize, 0.15, Math.PI * 2 - 0.15);
ctx.lineTo(0, -bodyHeight - headSize * 0.2);
ctx.closePath();
} else {
ctx.arc(0, -bodyHeight - headSize * 0.2, headSize, 0, Math.PI * 2);
}
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
ctx.stroke();
// Rayures sur la tête (verticales)
ctx.fillStyle = '#000000';
ctx.fillRect(-headSize * 0.4, -bodyHeight - headSize * 0.5, headSize * 0.15, headSize * 0.6);
ctx.fillRect(headSize * 0.25, -bodyHeight - headSize * 0.5, headSize * 0.15, headSize * 0.6);
// Oreilles pointues
ctx.beginPath();
// Oreille gauche
ctx.moveTo(-headSize * 0.6, -bodyHeight - headSize * 0.8);
ctx.lineTo(-headSize * 0.8, -bodyHeight - headSize * 1.4);
ctx.lineTo(-headSize * 0.4, -bodyHeight - headSize * 0.9);
ctx.closePath();
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.stroke();
// Rayure sur l'oreille gauche
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.moveTo(-headSize * 0.65, -bodyHeight - headSize * 0.95);
ctx.lineTo(-headSize * 0.75, -bodyHeight - headSize * 1.3);
ctx.lineTo(-headSize * 0.55, -bodyHeight - headSize * 1.0);
ctx.closePath();
ctx.fill();
// Oreille droite
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.moveTo(headSize * 0.6, -bodyHeight - headSize * 0.8);
ctx.lineTo(headSize * 0.8, -bodyHeight - headSize * 1.4);
ctx.lineTo(headSize * 0.4, -bodyHeight - headSize * 0.9);
ctx.closePath();
ctx.fill();
ctx.stroke();
// Rayure sur l'oreille droite
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.moveTo(headSize * 0.65, -bodyHeight - headSize * 0.95);
ctx.lineTo(headSize * 0.75, -bodyHeight - headSize * 1.3);
ctx.lineTo(headSize * 0.55, -bodyHeight - headSize * 1.0);
ctx.closePath();
ctx.fill();
// Yeux
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(-headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.15, 0, Math.PI * 2);
ctx.arc(headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.15, 0, Math.PI * 2);
ctx.fill();
// Pupilles
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.arc(-headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.08, 0, Math.PI * 2);
ctx.arc(headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.08, 0, Math.PI * 2);
ctx.fill();
// Reflets dans les yeux
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(-headSize * 0.32, -bodyHeight - headSize * 0.32, headSize * 0.03, 0, Math.PI * 2);
ctx.arc(headSize * 0.28, -bodyHeight - headSize * 0.32, headSize * 0.03, 0, Math.PI * 2);
ctx.fill();
// Queue (petite touffe)
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.arc(bodyWidth * 0.6, bodyHeight * 0.6, size * 0.2, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
} else {
// Forme ronde (par défaut)
if (this.mouthOpen) {
@ -2339,9 +2457,25 @@ class MenuGhost {
this.size = 30 + Math.random() * 20;
this.color = ['#ff0000', '#ff00ff', '#00ffff', '#ffa500'][Math.floor(Math.random() * 4)];
this.animation = Math.random() * Math.PI * 2;
this.isDestroyed = false;
this.destroyAnimation = 0;
}
// Vérifier si le curseur touche le fantôme
isPointInside(mouseX, mouseY) {
const distance = Math.sqrt(
Math.pow(mouseX - this.x, 2) +
Math.pow(mouseY - this.y, 2)
);
return distance < this.size * 0.7;
}
update() {
if (this.isDestroyed) {
this.destroyAnimation += 0.1;
return;
}
this.x += this.speedX;
this.y += this.speedY;
this.animation += 0.05;
@ -2360,6 +2494,33 @@ class MenuGhost {
}
draw() {
if (this.isDestroyed) {
// Animation de destruction (particules qui s'éparpillent)
if (this.destroyAnimation > 2) {
return;
}
menuCtx.save();
menuCtx.globalAlpha = 1 - (this.destroyAnimation / 2);
// Dessiner des particules qui s'éparpillent
const particleCount = 8;
for (let i = 0; i < particleCount; i++) {
const angle = (Math.PI * 2 / particleCount) * i + this.destroyAnimation * 2;
const distance = this.destroyAnimation * 30;
const particleX = this.x + Math.cos(angle) * distance;
const particleY = this.y + Math.sin(angle) * distance;
menuCtx.fillStyle = this.color;
menuCtx.beginPath();
menuCtx.arc(particleX, particleY, 4, 0, Math.PI * 2);
menuCtx.fill();
}
menuCtx.restore();
return;
}
menuCtx.save();
menuCtx.translate(this.x, this.y);
@ -2440,6 +2601,13 @@ function animateMenu() {
ghost.draw();
});
// Remplacer les fantômes complètement détruits
for (let i = 0; i < menuGhosts.length; i++) {
if (menuGhosts[i].isDestroyed && menuGhosts[i].destroyAnimation > 2) {
menuGhosts[i] = new MenuGhost();
}
}
menuAnimationFrame = requestAnimationFrame(animateMenu);
}
@ -2488,6 +2656,25 @@ if (mainMenu) {
menuObserver.observe(mainMenu, { attributes: true, attributeFilter: ['style'] });
}
// Gestion de la destruction des fantômes avec le curseur
let mouseX = 0;
let mouseY = 0;
menuCanvas.addEventListener('mousemove', (e) => {
const rect = menuCanvas.getBoundingClientRect();
mouseX = e.clientX - rect.left;
mouseY = e.clientY - rect.top;
// Vérifier les collisions avec les fantômes
menuGhosts.forEach(ghost => {
if (!ghost.isDestroyed && ghost.isPointInside(mouseX, mouseY)) {
// Détruire le fantôme
ghost.isDestroyed = true;
ghost.destroyAnimation = 0;
}
});
});
// === GESTION DU MENU ===
// Afficher le jeu
playBtn.addEventListener('click', () => {
@ -2748,6 +2935,120 @@ function startPreviewAnimation() {
};
ctx.fillStyle = colorMap[selectedColor] || '#ffd700';
}
} else if (selectedShape === 'zebre') {
// Dessiner un zèbre plus réaliste
const bodyWidth = size * 1.8;
const bodyHeight = size * 1.4;
// Corps (ellipse allongée)
ctx.beginPath();
ctx.ellipse(0, size * 0.2, bodyWidth, bodyHeight, 0, 0, Math.PI * 2);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
ctx.stroke();
// Rayures noires horizontales sur le corps
ctx.fillStyle = '#000000';
const stripeCount = 8;
const stripeSpacing = (bodyHeight * 2) / stripeCount;
for (let i = 0; i < stripeCount; i++) {
if (i % 2 === 1) { // Alterner les rayures
const yPos = -bodyHeight + (i * stripeSpacing);
ctx.beginPath();
ctx.ellipse(0, yPos + size * 0.2, bodyWidth * 0.95, stripeSpacing * 0.5, 0, 0, Math.PI * 2);
ctx.fill();
}
}
// Tête (cercle légèrement plus petit au-dessus du corps)
const headSize = size * 0.9;
ctx.beginPath();
if (mouthOpen) {
ctx.arc(0, -bodyHeight - headSize * 0.2, headSize, 0.15, Math.PI * 2 - 0.15);
ctx.lineTo(0, -bodyHeight - headSize * 0.2);
ctx.closePath();
} else {
ctx.arc(0, -bodyHeight - headSize * 0.2, headSize, 0, Math.PI * 2);
}
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
ctx.stroke();
// Rayures sur la tête (verticales)
ctx.fillStyle = '#000000';
ctx.fillRect(-headSize * 0.4, -bodyHeight - headSize * 0.5, headSize * 0.15, headSize * 0.6);
ctx.fillRect(headSize * 0.25, -bodyHeight - headSize * 0.5, headSize * 0.15, headSize * 0.6);
// Oreilles pointues
ctx.beginPath();
// Oreille gauche
ctx.moveTo(-headSize * 0.6, -bodyHeight - headSize * 0.8);
ctx.lineTo(-headSize * 0.8, -bodyHeight - headSize * 1.4);
ctx.lineTo(-headSize * 0.4, -bodyHeight - headSize * 0.9);
ctx.closePath();
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.stroke();
// Rayure sur l'oreille gauche
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.moveTo(-headSize * 0.65, -bodyHeight - headSize * 0.95);
ctx.lineTo(-headSize * 0.75, -bodyHeight - headSize * 1.3);
ctx.lineTo(-headSize * 0.55, -bodyHeight - headSize * 1.0);
ctx.closePath();
ctx.fill();
// Oreille droite
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.moveTo(headSize * 0.6, -bodyHeight - headSize * 0.8);
ctx.lineTo(headSize * 0.8, -bodyHeight - headSize * 1.4);
ctx.lineTo(headSize * 0.4, -bodyHeight - headSize * 0.9);
ctx.closePath();
ctx.fill();
ctx.stroke();
// Rayure sur l'oreille droite
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.moveTo(headSize * 0.65, -bodyHeight - headSize * 0.95);
ctx.lineTo(headSize * 0.75, -bodyHeight - headSize * 1.3);
ctx.lineTo(headSize * 0.55, -bodyHeight - headSize * 1.0);
ctx.closePath();
ctx.fill();
// Yeux
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(-headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.15, 0, Math.PI * 2);
ctx.arc(headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.15, 0, Math.PI * 2);
ctx.fill();
// Pupilles
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.arc(-headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.08, 0, Math.PI * 2);
ctx.arc(headSize * 0.3, -bodyHeight - headSize * 0.3, headSize * 0.08, 0, Math.PI * 2);
ctx.fill();
// Reflets dans les yeux
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(-headSize * 0.32, -bodyHeight - headSize * 0.32, headSize * 0.03, 0, Math.PI * 2);
ctx.arc(headSize * 0.28, -bodyHeight - headSize * 0.32, headSize * 0.03, 0, Math.PI * 2);
ctx.fill();
// Queue (petite touffe)
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.arc(bodyWidth * 0.6, bodyHeight * 0.6, size * 0.2, 0, Math.PI * 2);
ctx.fill();
} else {
// Dessiner un cercle
if (mouthOpen) {