amelioration jeu
This commit is contained in:
137
game.js
137
game.js
@ -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':
|
||||||
|
|||||||
@ -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 -->
|
||||||
|
|||||||
39
style.css
39
style.css
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user