amelioration jeu

This commit is contained in:
2025-12-01 22:46:43 +01:00
parent 502a462ec5
commit eab98868ef
3 changed files with 185 additions and 15 deletions

137
game.js
View File

@ -146,12 +146,16 @@ let maze = originalMaze.map(row => [...row]);
let score = 0; let score = 0;
let level = 1; let level = 1;
let gameRunning = true; let gameRunning = true;
let isPaused = false;
let totalDots = 0; let totalDots = 0;
let cherriesEaten = 0; let cherriesEaten = 0;
let isChangingLevel = false; let isChangingLevel = false;
let cherryEatenRecently = false; let cherryEatenRecently = false;
let cherryEatenTimer = 0; let cherryEatenTimer = 0;
let lives = 3; let lives = 3;
let dotsRemainingElement = document.getElementById('dotsRemaining');
let pursuitIndicator = document.getElementById('pursuitIndicator');
let pursuitTimerElement = document.getElementById('pursuitTimer');
class Pacman { class Pacman {
constructor() { constructor() {
@ -169,7 +173,7 @@ class Pacman {
} }
update() { update() {
if (!gameRunning) return; if (!gameRunning || isPaused) return;
this.mouthAngle += 0.2; this.mouthAngle += 0.2;
if (this.mouthAngle > Math.PI * 2) { if (this.mouthAngle > Math.PI * 2) {
@ -232,6 +236,9 @@ class Pacman {
score += 10; score += 10;
scoreElement.textContent = score; scoreElement.textContent = score;
totalDots--; totalDots--;
if (dotsRemainingElement) {
dotsRemainingElement.textContent = totalDots;
}
} else if (maze[this.y][this.x] === BONUS_CHERRY) { } else if (maze[this.y][this.x] === BONUS_CHERRY) {
if (isChangingLevel) { if (isChangingLevel) {
console.log('Changement de niveau en cours, cerise ignorée'); console.log('Changement de niveau en cours, cerise ignorée');
@ -248,6 +255,18 @@ class Pacman {
cherryEatenRecently = true; cherryEatenRecently = true;
cherryEatenTimer = Math.max(150, 300 - (level - 1) * 20); cherryEatenTimer = Math.max(150, 300 - (level - 1) * 20);
// Rendre tous les fantômes vulnérables
const vulnerableTime = Math.max(180, 360 - (level - 1) * 30);
for (let ghost of ghosts) {
ghost.isVulnerable = true;
ghost.vulnerableTimer = vulnerableTime;
}
// Afficher l'indicateur de poursuite
if (pursuitIndicator) {
pursuitIndicator.style.display = 'block';
}
console.log('Après incrémentation, cherriesEaten:', cherriesEaten, 'isChangingLevel:', isChangingLevel); console.log('Après incrémentation, cherriesEaten:', cherriesEaten, 'isChangingLevel:', isChangingLevel);
if (cherriesEaten >= 4 && !isChangingLevel) { if (cherriesEaten >= 4 && !isChangingLevel) {
@ -300,6 +319,10 @@ class Ghost {
this.pixelY = this.y * CELL_SIZE + CELL_SIZE / 2; this.pixelY = this.y * CELL_SIZE + CELL_SIZE / 2;
this.moveCounter = 0; this.moveCounter = 0;
this.moveInterval = 30; this.moveInterval = 30;
this.isVulnerable = false;
this.vulnerableTimer = 0;
this.startX = x;
this.startY = y;
} }
updateSpeed() { updateSpeed() {
@ -307,12 +330,24 @@ class Ghost {
} }
update() { update() {
if (!gameRunning) return; if (!gameRunning || isPaused) return;
// Gestion de la vulnérabilité
if (this.isVulnerable) {
this.vulnerableTimer--;
if (this.vulnerableTimer <= 0) {
this.isVulnerable = false;
}
}
if (cherryEatenTimer > 0) { if (cherryEatenTimer > 0) {
cherryEatenTimer--; cherryEatenTimer--;
} else { } else {
cherryEatenRecently = false; cherryEatenRecently = false;
// Rendre les fantômes vulnérables quand une cerise est mangée
if (!this.isVulnerable && cherryEatenTimer === 0) {
// La vulnérabilité est gérée dans collectDot()
}
} }
this.moveInterval = Math.max(15, 30 - (level - 1) * 2); this.moveInterval = Math.max(15, 30 - (level - 1) * 2);
@ -423,7 +458,13 @@ class Ghost {
const size = CELL_SIZE * 0.75; const size = CELL_SIZE * 0.75;
// Si vulnérable, afficher en bleu clignotant
if (this.isVulnerable) {
const flash = Math.floor(this.vulnerableTimer / 10) % 2;
ctx.fillStyle = flash === 0 ? '#0000ff' : '#ffffff';
} else {
ctx.fillStyle = this.color; ctx.fillStyle = this.color;
}
ctx.strokeStyle = '#000000'; ctx.strokeStyle = '#000000';
ctx.lineWidth = 2; ctx.lineWidth = 2;
@ -579,6 +620,10 @@ function countDots() {
} }
} }
} }
// Mettre à jour l'affichage
if (dotsRemainingElement) {
dotsRemainingElement.textContent = totalDots;
}
} }
function drawMaze() { function drawMaze() {
@ -611,7 +656,7 @@ function drawMaze() {
} }
function checkCollisions() { function checkCollisions() {
if (!gameRunning) return; if (!gameRunning || isPaused) return;
for (let ghost of ghosts) { for (let ghost of ghosts) {
const distance = Math.sqrt( const distance = Math.sqrt(
@ -620,6 +665,20 @@ function checkCollisions() {
); );
if (distance < CELL_SIZE * 0.6) { if (distance < CELL_SIZE * 0.6) {
if (ghost.isVulnerable) {
// Manger le fantôme
score += 200;
scoreElement.textContent = score;
ghost.isVulnerable = false;
ghost.vulnerableTimer = 0;
// Réinitialiser la position du fantôme
ghost.x = ghost.startX;
ghost.y = ghost.startY;
ghost.pixelX = ghost.x * CELL_SIZE + CELL_SIZE / 2;
ghost.pixelY = ghost.y * CELL_SIZE + CELL_SIZE / 2;
ghost.direction = Math.floor(Math.random() * 4);
} else {
// Perdre une vie
lives--; lives--;
updateLivesDisplay(); updateLivesDisplay();
@ -634,6 +693,7 @@ function checkCollisions() {
} }
} }
} }
}
function gameLoop() { function gameLoop() {
if (isChangingLevel || !gameRunning) { if (isChangingLevel || !gameRunning) {
@ -644,9 +704,40 @@ function gameLoop() {
} }
drawMaze(); drawMaze();
// Gestion de la pause
if (isPaused) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffd700';
ctx.font = 'bold 48px "Press Start 2P"';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('PAUSE', canvas.width/2, canvas.height/2);
ctx.font = 'bold 16px "Press Start 2P"';
ctx.fillText('Appuyez sur ESPACE ou ECHAP', canvas.width/2, canvas.height/2 + 40);
requestAnimationFrame(gameLoop);
return;
}
pacman.update(); pacman.update();
pacman.draw(); pacman.draw();
// Mettre à jour l'indicateur de poursuite
if (pursuitIndicator && cherryEatenTimer > 0) {
const seconds = Math.ceil(cherryEatenTimer / 60);
if (pursuitTimerElement) {
pursuitTimerElement.textContent = seconds;
}
// Vérifier si tous les fantômes sont encore vulnérables
const allVulnerable = ghosts.every(g => g.isVulnerable);
if (!allVulnerable && pursuitIndicator.style.display !== 'none') {
pursuitIndicator.style.display = 'none';
}
} else if (pursuitIndicator) {
pursuitIndicator.style.display = 'none';
}
for (let ghost of ghosts) { for (let ghost of ghosts) {
ghost.update(); ghost.update();
ghost.draw(); ghost.draw();
@ -705,11 +796,16 @@ function restartCurrentLevel() {
for (let ghost of ghosts) { for (let ghost of ghosts) {
ghost.updateSpeed(); ghost.updateSpeed();
ghost.isVulnerable = false;
ghost.vulnerableTimer = 0;
} }
cherriesEaten = 0; cherriesEaten = 0;
cherryEatenRecently = false; cherryEatenRecently = false;
cherryEatenTimer = 0; cherryEatenTimer = 0;
if (pursuitIndicator) {
pursuitIndicator.style.display = 'none';
}
statusElement.textContent = `Niveau ${level} - Recommencement !`; statusElement.textContent = `Niveau ${level} - Recommencement !`;
statusElement.style.color = '#ff6b6b'; statusElement.style.color = '#ff6b6b';
@ -796,6 +892,13 @@ function nextLevel() {
for (let ghost of ghosts) { for (let ghost of ghosts) {
ghost.updateSpeed(); ghost.updateSpeed();
ghost.isVulnerable = false;
ghost.vulnerableTimer = 0;
}
cherryEatenTimer = 0;
if (pursuitIndicator) {
pursuitIndicator.style.display = 'none';
} }
placeBonuses(); placeBonuses();
@ -1024,6 +1127,7 @@ function initGame() {
level = 1; level = 1;
lives = 3; lives = 3;
cherriesEaten = 0; cherriesEaten = 0;
isPaused = false;
scoreElement.textContent = score; scoreElement.textContent = score;
levelElement.textContent = level; levelElement.textContent = level;
updateLivesDisplay(); updateLivesDisplay();
@ -1032,6 +1136,9 @@ function initGame() {
statusElement.style.color = '#ffd700'; statusElement.style.color = '#ffd700';
restartBtn.style.display = 'none'; restartBtn.style.display = 'none';
hideGameOver(); hideGameOver();
if (pursuitIndicator) {
pursuitIndicator.style.display = 'none';
}
pacman = new Pacman(); pacman = new Pacman();
pacman.speed = pacman.baseSpeed * (1 + (level - 1) * 0.05); pacman.speed = pacman.baseSpeed * (1 + (level - 1) * 0.05);
@ -1042,6 +1149,12 @@ function initGame() {
for (let ghost of ghosts) { for (let ghost of ghosts) {
ghost.updateSpeed(); ghost.updateSpeed();
ghost.isVulnerable = false;
ghost.vulnerableTimer = 0;
}
if (pursuitIndicator) {
pursuitIndicator.style.display = 'none';
} }
placeBonuses(); placeBonuses();
@ -1050,7 +1163,23 @@ function initGame() {
} }
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if (!gameRunning) return; // Système de pause
if (e.key === 'Escape' || e.key === ' ') {
if (gameRunning && !isChangingLevel) {
isPaused = !isPaused;
if (isPaused) {
statusElement.textContent = 'PAUSE';
statusElement.style.color = '#ffd700';
} else {
statusElement.textContent = 'En jeu';
statusElement.style.color = '#ffd700';
}
e.preventDefault();
return;
}
}
if (!gameRunning || isPaused) return;
switch(e.key) { switch(e.key) {
case 'ArrowUp': case 'ArrowUp':

View File

@ -45,8 +45,12 @@
<div class="score">Score: <span id="score">0</span></div> <div class="score">Score: <span id="score">0</span></div>
<div class="level">Niveau: <span id="level">1</span></div> <div class="level">Niveau: <span id="level">1</span></div>
<div class="lives">Vies: <span id="lives"><span class="heart"></span><span class="heart"></span><span class="heart"></span></span></div> <div class="lives">Vies: <span id="lives"><span class="heart"></span><span class="heart"></span><span class="heart"></span></span></div>
<div class="dots-remaining">Pastilles: <span id="dotsRemaining">0</span></div>
<div class="status" id="status">Prêt à jouer</div> <div class="status" id="status">Prêt à jouer</div>
</div> </div>
<div class="pursuit-indicator" id="pursuitIndicator" style="display: none;">
<span class="pursuit-text">👻 Poursuite active: <span id="pursuitTimer">0</span>s</span>
</div>
<canvas id="gameCanvas" width="600" height="600"></canvas> <canvas id="gameCanvas" width="600" height="600"></canvas>
<!-- Contrôles tactiles mobile --> <!-- Contrôles tactiles mobile -->

View File

@ -452,7 +452,7 @@ h1 {
flex-wrap: wrap; flex-wrap: wrap;
} }
.score, .level, .lives { .score, .level, .lives, .dots-remaining {
font-size: 0.9em; font-size: 0.9em;
font-weight: bold; font-weight: bold;
background: rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.4);
@ -462,6 +462,10 @@ h1 {
transition: all 0.3s; transition: all 0.3s;
} }
.dots-remaining {
color: #00ffff;
}
.score.updated { .score.updated {
animation: scoreUp 0.3s ease-out; animation: scoreUp 0.3s ease-out;
} }
@ -490,6 +494,39 @@ h1 {
text-shadow: 0 0 10px rgba(255, 215, 0, 0.5); text-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
} }
/* === INDICATEUR DE poursuite === */
.pursuit-indicator {
margin: 15px auto;
padding: 12px 25px;
background: linear-gradient(180deg, rgba(255, 0, 0, 0.3), rgba(255, 0, 0, 0.1));
border: 2px solid #ff0000;
border-radius: 10px;
text-align: center;
animation: pursuitPulse 1s ease-in-out infinite;
max-width: 300px;
}
@keyframes pursuitPulse {
0%, 100% {
box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);
}
50% {
box-shadow: 0 0 20px rgba(255, 0, 0, 0.8);
}
}
.pursuit-text {
font-size: 0.8em;
color: #ff0000;
text-shadow: 0 0 10px rgba(255, 0, 0, 0.8);
}
#pursuitTimer {
color: #ffff00;
font-weight: bold;
font-size: 1.2em;
}
/* === CANVAS AVEC GLOW ET EFFET 3D === */ /* === CANVAS AVEC GLOW ET EFFET 3D === */
#gameCanvas { #gameCanvas {
border: 4px solid #ffd700; border: 4px solid #ffd700;