premier
This commit is contained in:
797
game.js
Normal file
797
game.js
Normal file
@ -0,0 +1,797 @@
|
|||||||
|
const canvas = document.getElementById('gameCanvas');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
const scoreElement = document.getElementById('score');
|
||||||
|
const levelElement = document.getElementById('level');
|
||||||
|
const statusElement = document.getElementById('status');
|
||||||
|
const restartBtn = document.getElementById('restartBtn');
|
||||||
|
const usernameInput = document.getElementById('username');
|
||||||
|
const leaderboardElement = document.getElementById('leaderboard');
|
||||||
|
|
||||||
|
const CELL_SIZE = 20;
|
||||||
|
const COLS = 30;
|
||||||
|
const ROWS = 30;
|
||||||
|
|
||||||
|
const WALL = 1;
|
||||||
|
const DOT = 2;
|
||||||
|
const EMPTY = 0;
|
||||||
|
const TUNNEL = 3;
|
||||||
|
const BONUS_CHERRY = 4;
|
||||||
|
const BONUS_LUDO = 5;
|
||||||
|
|
||||||
|
const originalMaze1 = [
|
||||||
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,1,1,2,2,2,2,1,1,1,1,2,2,2,2,1,1,2,2,2,2,2,2,1],
|
||||||
|
[1,1,1,1,1,1,2,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,2,1,1,1,1,1,1],
|
||||||
|
[0,0,0,0,0,1,2,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,0,1,1,1,3,3,3,3,1,1,1,0,1,1,2,1,0,0,0,0,0],
|
||||||
|
[1,1,1,1,1,1,2,1,1,0,1,0,0,0,0,0,0,0,0,1,0,1,1,2,1,1,1,1,1,1],
|
||||||
|
[0,0,0,0,0,0,2,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,0,0,0],
|
||||||
|
[1,1,1,1,1,1,2,1,1,0,1,0,0,0,0,0,0,0,0,1,0,1,1,2,1,1,1,1,1,1],
|
||||||
|
[0,0,0,0,0,1,2,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,2,1,0,0,0,0,0],
|
||||||
|
[1,1,1,1,1,1,2,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,2,1,1,1,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,1,1,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,1,1,2,2,2,1],
|
||||||
|
[1,1,1,2,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,1],
|
||||||
|
[1,1,1,2,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,1,1,2,2,2,2,1,1,1,1,2,2,2,2,1,1,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
|
||||||
|
];
|
||||||
|
|
||||||
|
const originalMaze2 = [
|
||||||
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,2,1,1,2,1,1,1,1,2,1,1,2,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,1,1,2,1,1,2,1,1,2,1,1,1,1,2,1,1,2,1,1,2,1,1,2,2,2,1],
|
||||||
|
[1,1,1,2,1,1,2,2,2,2,1,1,2,2,2,2,2,2,1,1,2,2,2,2,1,1,2,1,1,1],
|
||||||
|
[1,2,2,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,2,2,2,2,2,1],
|
||||||
|
[1,1,1,1,1,1,2,1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1,2,1,1,1,1,1,1],
|
||||||
|
[0,0,0,0,0,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,2,1,0,0,0,0,0,0,0,0,1,2,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,2,1,0,1,1,3,3,1,1,0,1,2,1,1,2,1,0,0,0,0,0],
|
||||||
|
[1,1,1,1,1,1,2,1,1,2,1,0,1,0,0,0,0,1,0,1,2,1,1,2,1,1,1,1,1,1],
|
||||||
|
[0,0,0,0,0,0,2,0,0,2,0,0,1,0,0,0,0,1,0,0,2,0,0,2,0,0,0,0,0,0],
|
||||||
|
[1,1,1,1,1,1,2,1,1,2,1,0,1,0,0,0,0,1,0,1,2,1,1,2,1,1,1,1,1,1],
|
||||||
|
[0,0,0,0,0,1,2,1,1,2,1,0,1,1,1,1,1,1,0,1,2,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,2,1,0,0,0,0,0,0,0,0,1,2,1,1,2,1,0,0,0,0,0],
|
||||||
|
[0,0,0,0,0,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,0,0,0,0,0],
|
||||||
|
[1,1,1,1,1,1,2,1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1,2,1,1,1,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,1,1,1,2,1,1,2,1,1,1,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,1,1,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,1,1,2,2,2,1],
|
||||||
|
[1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
|
||||||
|
];
|
||||||
|
|
||||||
|
const originalMaze3 = [
|
||||||
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,1],
|
||||||
|
[1,1,1,2,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,2,1,1,0,0,0,0,0,0,1,1,2,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,2,1,1,0,1,1,1,1,0,1,1,2,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,1,1,0,1,3,3,1,0,1,1,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,1,1,1,1,1,1,1,1,2,1,1,0,1,1,1,1,0,1,1,2,1,1,1,1,1,1,1,1,1],
|
||||||
|
[0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0],
|
||||||
|
[1,1,1,1,1,1,1,1,1,2,1,1,0,1,1,1,1,0,1,1,2,1,1,1,1,1,1,1,1,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,1,1,0,1,3,3,1,0,1,1,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,2,1,1,0,1,1,1,1,0,1,1,2,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,2,1,1,0,0,0,0,0,0,1,1,2,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,2,2,2,2,2,1],
|
||||||
|
[1,1,1,2,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,1],
|
||||||
|
[1,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,2,1,1,1,1,1,2,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1],
|
||||||
|
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
|
||||||
|
];
|
||||||
|
|
||||||
|
const mazeVariants = [originalMaze1, originalMaze2, originalMaze3];
|
||||||
|
let originalMaze = originalMaze1;
|
||||||
|
let currentMazeIndex = 0;
|
||||||
|
|
||||||
|
let maze = originalMaze.map(row => [...row]);
|
||||||
|
|
||||||
|
let score = 0;
|
||||||
|
let level = 1;
|
||||||
|
let gameRunning = true;
|
||||||
|
let totalDots = 0;
|
||||||
|
const TEST_MODE = true;
|
||||||
|
let cherriesEaten = 0;
|
||||||
|
let isChangingLevel = false;
|
||||||
|
|
||||||
|
class Pacman {
|
||||||
|
constructor() {
|
||||||
|
this.x = 14;
|
||||||
|
this.y = 23;
|
||||||
|
this.direction = 0;
|
||||||
|
this.nextDirection = 0;
|
||||||
|
this.mouthAngle = 0;
|
||||||
|
this.mouthOpen = true;
|
||||||
|
this.speed = 0.15;
|
||||||
|
this.pixelX = this.x * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
this.pixelY = this.y * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (!gameRunning) return;
|
||||||
|
|
||||||
|
this.mouthAngle += 0.2;
|
||||||
|
if (this.mouthAngle > Math.PI * 2) {
|
||||||
|
this.mouthAngle = 0;
|
||||||
|
this.mouthOpen = !this.mouthOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gridX = Math.floor(this.pixelX / CELL_SIZE);
|
||||||
|
const gridY = Math.floor(this.pixelY / CELL_SIZE);
|
||||||
|
|
||||||
|
if (this.canMove(this.nextDirection)) {
|
||||||
|
this.direction = this.nextDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.canMove(this.direction)) {
|
||||||
|
const dx = [0, 1, 0, -1];
|
||||||
|
const dy = [-1, 0, 1, 0];
|
||||||
|
|
||||||
|
this.pixelX += dx[this.direction] * this.speed * CELL_SIZE;
|
||||||
|
this.pixelY += dy[this.direction] * this.speed * CELL_SIZE;
|
||||||
|
|
||||||
|
if (this.pixelX < 0) {
|
||||||
|
this.pixelX = COLS * CELL_SIZE;
|
||||||
|
} else if (this.pixelX > COLS * CELL_SIZE) {
|
||||||
|
this.pixelX = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.pixelX = gridX * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
this.pixelY = gridY * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.x = Math.floor(this.pixelX / CELL_SIZE);
|
||||||
|
this.y = Math.floor(this.pixelY / CELL_SIZE);
|
||||||
|
|
||||||
|
this.collectDot();
|
||||||
|
}
|
||||||
|
|
||||||
|
canMove(direction) {
|
||||||
|
const dx = [0, 1, 0, -1];
|
||||||
|
const dy = [-1, 0, 1, 0];
|
||||||
|
|
||||||
|
const nextX = Math.floor((this.pixelX + dx[direction] * CELL_SIZE * 0.5) / CELL_SIZE);
|
||||||
|
const nextY = Math.floor((this.pixelY + dy[direction] * CELL_SIZE * 0.5) / CELL_SIZE);
|
||||||
|
|
||||||
|
if (nextX < 0 || nextX >= COLS || nextY < 0 || nextY >= ROWS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maze[nextY][nextX] !== WALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
collectDot() {
|
||||||
|
if (maze[this.y][this.x] === DOT) {
|
||||||
|
maze[this.y][this.x] = EMPTY;
|
||||||
|
score += 10;
|
||||||
|
scoreElement.textContent = score;
|
||||||
|
totalDots--;
|
||||||
|
|
||||||
|
if (totalDots === 0 && !isChangingLevel) {
|
||||||
|
console.log('Toutes les pastilles collectées, passage au niveau suivant');
|
||||||
|
nextLevel();
|
||||||
|
}
|
||||||
|
} else if (maze[this.y][this.x] === BONUS_CHERRY) {
|
||||||
|
if (isChangingLevel) {
|
||||||
|
console.log('Changement de niveau en cours, cerise ignorée');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Cerise collectée, cherriesEaten:', cherriesEaten);
|
||||||
|
maze[this.y][this.x] = EMPTY;
|
||||||
|
score += 100;
|
||||||
|
scoreElement.textContent = score;
|
||||||
|
bonuses = bonuses.filter(b => !(b.x === this.x && b.y === this.y && b.type === BONUS_CHERRY));
|
||||||
|
cherriesEaten++;
|
||||||
|
|
||||||
|
console.log('Après incrémentation, cherriesEaten:', cherriesEaten, 'TEST_MODE:', TEST_MODE, 'isChangingLevel:', isChangingLevel);
|
||||||
|
|
||||||
|
if (TEST_MODE && cherriesEaten >= 2 && !isChangingLevel) {
|
||||||
|
console.log('2 cerises mangées, appel de nextLevel()');
|
||||||
|
cherriesEaten = 0;
|
||||||
|
nextLevel();
|
||||||
|
}
|
||||||
|
} else if (maze[this.y][this.x] === BONUS_LUDO) {
|
||||||
|
maze[this.y][this.x] = EMPTY;
|
||||||
|
score += 200;
|
||||||
|
scoreElement.textContent = score;
|
||||||
|
bonuses = bonuses.filter(b => !(b.x === this.x && b.y === this.y && b.type === BONUS_LUDO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(this.pixelX, this.pixelY);
|
||||||
|
|
||||||
|
const rotation = [Math.PI * 1.5, 0, Math.PI * 0.5, Math.PI];
|
||||||
|
ctx.rotate(rotation[this.direction]);
|
||||||
|
|
||||||
|
ctx.fillStyle = '#ffd700';
|
||||||
|
ctx.beginPath();
|
||||||
|
|
||||||
|
if (this.mouthOpen) {
|
||||||
|
ctx.arc(0, 0, CELL_SIZE * 0.4, 0.2, Math.PI * 2 - 0.2);
|
||||||
|
} else {
|
||||||
|
ctx.arc(0, 0, CELL_SIZE * 0.4, 0, Math.PI * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.lineTo(0, 0);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ghost {
|
||||||
|
constructor(x, y, color) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.color = color;
|
||||||
|
this.direction = Math.floor(Math.random() * 4);
|
||||||
|
this.baseSpeed = 0.1;
|
||||||
|
this.speed = this.baseSpeed;
|
||||||
|
this.pixelX = this.x * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
this.pixelY = this.y * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
this.moveCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSpeed() {
|
||||||
|
this.speed = this.baseSpeed * (1 + (level - 1) * 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (!gameRunning) return;
|
||||||
|
|
||||||
|
this.moveCounter++;
|
||||||
|
|
||||||
|
if (this.moveCounter > 30 || !this.canMove(this.direction)) {
|
||||||
|
const possibleDirections = [];
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
if (this.canMove(i)) {
|
||||||
|
possibleDirections.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (possibleDirections.length > 0) {
|
||||||
|
this.direction = possibleDirections[Math.floor(Math.random() * possibleDirections.length)];
|
||||||
|
}
|
||||||
|
this.moveCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dx = [0, 1, 0, -1];
|
||||||
|
const dy = [-1, 0, 1, 0];
|
||||||
|
|
||||||
|
this.pixelX += dx[this.direction] * this.speed * CELL_SIZE;
|
||||||
|
this.pixelY += dy[this.direction] * this.speed * CELL_SIZE;
|
||||||
|
|
||||||
|
if (this.pixelX < 0) {
|
||||||
|
this.pixelX = COLS * CELL_SIZE;
|
||||||
|
} else if (this.pixelX > COLS * CELL_SIZE) {
|
||||||
|
this.pixelX = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.x = Math.floor(this.pixelX / CELL_SIZE);
|
||||||
|
this.y = Math.floor(this.pixelY / CELL_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
canMove(direction) {
|
||||||
|
const dx = [0, 1, 0, -1];
|
||||||
|
const dy = [-1, 0, 1, 0];
|
||||||
|
|
||||||
|
const nextX = Math.floor((this.pixelX + dx[direction] * CELL_SIZE * 0.5) / CELL_SIZE);
|
||||||
|
const nextY = Math.floor((this.pixelY + dy[direction] * CELL_SIZE * 0.5) / CELL_SIZE);
|
||||||
|
|
||||||
|
if (nextX < 0 || nextX >= COLS || nextY < 0 || nextY >= ROWS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maze[nextY][nextX] !== WALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(this.pixelX, this.pixelY);
|
||||||
|
ctx.fillStyle = this.color;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(0, -CELL_SIZE * 0.15, CELL_SIZE * 0.3, Math.PI, 0, false);
|
||||||
|
ctx.rect(-CELL_SIZE * 0.3, -CELL_SIZE * 0.15, CELL_SIZE * 0.6, CELL_SIZE * 0.45);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(-CELL_SIZE * 0.3, CELL_SIZE * 0.3, CELL_SIZE * 0.2, CELL_SIZE * 0.2);
|
||||||
|
ctx.rect(-CELL_SIZE * 0.1, CELL_SIZE * 0.3, CELL_SIZE * 0.2, CELL_SIZE * 0.2);
|
||||||
|
ctx.rect(CELL_SIZE * 0.1, CELL_SIZE * 0.3, CELL_SIZE * 0.2, CELL_SIZE * 0.2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.fillStyle = '#fff';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(-CELL_SIZE * 0.15, -CELL_SIZE * 0.1, CELL_SIZE * 0.08, 0, Math.PI * 2);
|
||||||
|
ctx.arc(CELL_SIZE * 0.15, -CELL_SIZE * 0.1, CELL_SIZE * 0.08, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.fillStyle = '#000';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(-CELL_SIZE * 0.15, -CELL_SIZE * 0.1, CELL_SIZE * 0.04, 0, Math.PI * 2);
|
||||||
|
ctx.arc(CELL_SIZE * 0.15, -CELL_SIZE * 0.1, CELL_SIZE * 0.04, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bonus {
|
||||||
|
constructor(x, y, type) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.type = type;
|
||||||
|
this.animation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.animation += 0.1;
|
||||||
|
if (this.animation > Math.PI * 2) {
|
||||||
|
this.animation = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
const cellX = this.x * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
const cellY = this.y * CELL_SIZE + CELL_SIZE / 2;
|
||||||
|
const scale = 1 + Math.sin(this.animation) * 0.2;
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(cellX, cellY);
|
||||||
|
ctx.scale(scale, scale);
|
||||||
|
|
||||||
|
if (this.type === BONUS_CHERRY) {
|
||||||
|
ctx.fillStyle = '#ff0000';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(0, 0, CELL_SIZE * 0.25, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.fillStyle = '#00ff00';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(-CELL_SIZE * 0.15, -CELL_SIZE * 0.2, CELL_SIZE * 0.1, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.strokeStyle = '#00aa00';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(-CELL_SIZE * 0.15, -CELL_SIZE * 0.3);
|
||||||
|
ctx.lineTo(-CELL_SIZE * 0.25, -CELL_SIZE * 0.4);
|
||||||
|
ctx.stroke();
|
||||||
|
} else if (this.type === BONUS_LUDO) {
|
||||||
|
ctx.fillStyle = '#ffd700';
|
||||||
|
ctx.font = `bold ${CELL_SIZE * 0.4}px Arial`;
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
ctx.textBaseline = 'middle';
|
||||||
|
ctx.fillText('L', 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pacman = new Pacman();
|
||||||
|
const ghosts = [
|
||||||
|
new Ghost(14, 11, '#ff0000'),
|
||||||
|
new Ghost(15, 11, '#ff00ff'),
|
||||||
|
new Ghost(14, 12, '#00ffff'),
|
||||||
|
new Ghost(15, 12, '#ffa500')
|
||||||
|
];
|
||||||
|
|
||||||
|
let bonuses = [];
|
||||||
|
|
||||||
|
function countDots() {
|
||||||
|
totalDots = 0;
|
||||||
|
if (!maze || maze.length === 0) {
|
||||||
|
console.error('countDots() - maze est vide ou undefined');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let y = 0; y < ROWS; y++) {
|
||||||
|
if (!maze[y]) {
|
||||||
|
console.error(`countDots() - maze[${y}] est undefined`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (let x = 0; x < COLS; x++) {
|
||||||
|
if (maze[y][x] === DOT) {
|
||||||
|
totalDots++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawMaze() {
|
||||||
|
ctx.fillStyle = '#000';
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
for (let y = 0; y < ROWS; y++) {
|
||||||
|
for (let x = 0; x < COLS; x++) {
|
||||||
|
const cellX = x * CELL_SIZE;
|
||||||
|
const cellY = y * CELL_SIZE;
|
||||||
|
|
||||||
|
if (maze[y][x] === WALL) {
|
||||||
|
ctx.fillStyle = '#0000ff';
|
||||||
|
ctx.fillRect(cellX, cellY, CELL_SIZE, CELL_SIZE);
|
||||||
|
ctx.strokeStyle = '#000080';
|
||||||
|
ctx.strokeRect(cellX, cellY, CELL_SIZE, CELL_SIZE);
|
||||||
|
} else if (maze[y][x] === DOT) {
|
||||||
|
ctx.fillStyle = '#fff';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cellX + CELL_SIZE / 2, cellY + CELL_SIZE / 2, 2, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let bonus of bonuses) {
|
||||||
|
bonus.update();
|
||||||
|
bonus.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCollisions() {
|
||||||
|
if (!gameRunning) return;
|
||||||
|
|
||||||
|
for (let ghost of ghosts) {
|
||||||
|
const distance = Math.sqrt(
|
||||||
|
Math.pow(pacman.pixelX - ghost.pixelX, 2) +
|
||||||
|
Math.pow(pacman.pixelY - ghost.pixelY, 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distance < CELL_SIZE * 0.6) {
|
||||||
|
gameRunning = false;
|
||||||
|
statusElement.textContent = 'Game Over !';
|
||||||
|
restartBtn.style.display = 'block';
|
||||||
|
saveScore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gameLoop() {
|
||||||
|
if (isChangingLevel || !gameRunning) {
|
||||||
|
if (isChangingLevel) {
|
||||||
|
console.log('gameLoop() - Changement de niveau en cours, arrêt');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawMaze();
|
||||||
|
pacman.update();
|
||||||
|
pacman.draw();
|
||||||
|
|
||||||
|
for (let ghost of ghosts) {
|
||||||
|
ghost.update();
|
||||||
|
ghost.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCollisions();
|
||||||
|
|
||||||
|
if (gameRunning && !isChangingLevel) {
|
||||||
|
requestAnimationFrame(gameLoop);
|
||||||
|
} else {
|
||||||
|
console.log('gameLoop() - Arrêt de la boucle, gameRunning:', gameRunning, 'isChangingLevel:', isChangingLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextLevel() {
|
||||||
|
console.log('=== nextLevel() appelée ===');
|
||||||
|
console.log('gameRunning:', gameRunning, 'isChangingLevel:', isChangingLevel);
|
||||||
|
|
||||||
|
if (!gameRunning || isChangingLevel) {
|
||||||
|
console.log('nextLevel() annulée - gameRunning:', gameRunning, 'isChangingLevel:', isChangingLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Début du changement de niveau');
|
||||||
|
isChangingLevel = true;
|
||||||
|
const wasRunning = gameRunning;
|
||||||
|
gameRunning = false;
|
||||||
|
console.log('gameRunning mis à false, wasRunning:', wasRunning);
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
console.log('Dans requestAnimationFrame, changement du niveau');
|
||||||
|
level++;
|
||||||
|
console.log('Nouveau niveau:', level);
|
||||||
|
levelElement.textContent = level;
|
||||||
|
cherriesEaten = 0;
|
||||||
|
|
||||||
|
const mazeIndex = (level - 1) % mazeVariants.length;
|
||||||
|
console.log('Index du labyrinthe:', mazeIndex);
|
||||||
|
currentMazeIndex = mazeIndex;
|
||||||
|
const newMaze = mazeVariants[mazeIndex];
|
||||||
|
|
||||||
|
console.log('Création du nouveau labyrinthe');
|
||||||
|
console.log('newMaze.length:', newMaze.length, 'ROWS:', ROWS);
|
||||||
|
console.log('newMaze[0]?.length:', newMaze[0]?.length, 'COLS:', COLS);
|
||||||
|
|
||||||
|
if (!newMaze || newMaze.length !== ROWS) {
|
||||||
|
console.error('Erreur: Le nouveau labyrinthe a une taille incorrecte:', newMaze?.length);
|
||||||
|
isChangingLevel = false;
|
||||||
|
gameRunning = wasRunning;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
maze = [];
|
||||||
|
for (let i = 0; i < newMaze.length; i++) {
|
||||||
|
if (!newMaze[i] || newMaze[i].length !== COLS) {
|
||||||
|
console.error(`Erreur: Ligne ${i} du labyrinthe a une taille incorrecte:`, newMaze[i]?.length);
|
||||||
|
}
|
||||||
|
maze[i] = [...newMaze[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Labyrinthe copié, maze.length:', maze.length);
|
||||||
|
|
||||||
|
randomizeMaze();
|
||||||
|
|
||||||
|
countDots();
|
||||||
|
console.log('Total dots:', totalDots);
|
||||||
|
|
||||||
|
bonuses = [];
|
||||||
|
|
||||||
|
console.log('Réinitialisation de Pacman et des fantômes');
|
||||||
|
pacman = new Pacman();
|
||||||
|
ghosts[0] = new Ghost(14, 11, '#ff0000');
|
||||||
|
ghosts[1] = new Ghost(15, 11, '#ff00ff');
|
||||||
|
ghosts[2] = new Ghost(14, 12, '#00ffff');
|
||||||
|
ghosts[3] = new Ghost(15, 12, '#ffa500');
|
||||||
|
|
||||||
|
for (let ghost of ghosts) {
|
||||||
|
ghost.updateSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
placeBonuses();
|
||||||
|
console.log('Bonus placés, nombre:', bonuses.length);
|
||||||
|
|
||||||
|
statusElement.textContent = `Niveau ${level} - Labyrinthe ${mazeIndex + 1} !`;
|
||||||
|
statusElement.style.color = '#00ff00';
|
||||||
|
|
||||||
|
console.log('Redessin du labyrinthe');
|
||||||
|
drawMaze();
|
||||||
|
pacman.draw();
|
||||||
|
for (let ghost of ghosts) {
|
||||||
|
ghost.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Attente de 2 secondes avant redémarrage');
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('Redémarrage de la boucle de jeu');
|
||||||
|
isChangingLevel = false;
|
||||||
|
gameRunning = wasRunning;
|
||||||
|
console.log('isChangingLevel:', isChangingLevel, 'gameRunning:', gameRunning);
|
||||||
|
if (gameRunning) {
|
||||||
|
statusElement.textContent = 'En jeu';
|
||||||
|
statusElement.style.color = '#ffd700';
|
||||||
|
console.log('Appel de gameLoop() pour redémarrer');
|
||||||
|
gameLoop();
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomizeMaze() {
|
||||||
|
const modificationRate = 0.15;
|
||||||
|
const changes = Math.floor(ROWS * COLS * modificationRate);
|
||||||
|
|
||||||
|
console.log('Modification aléatoire du labyrinthe,', changes, 'changements');
|
||||||
|
|
||||||
|
for (let i = 0; i < changes; i++) {
|
||||||
|
const x = Math.floor(Math.random() * COLS);
|
||||||
|
const y = Math.floor(Math.random() * ROWS);
|
||||||
|
|
||||||
|
if (x === 0 || x === COLS - 1 || y === 0 || y === ROWS - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentCell = maze[y][x];
|
||||||
|
|
||||||
|
if (currentCell === WALL) {
|
||||||
|
if (Math.random() < 0.7) {
|
||||||
|
maze[y][x] = DOT;
|
||||||
|
} else {
|
||||||
|
maze[y][x] = EMPTY;
|
||||||
|
}
|
||||||
|
} else if (currentCell === EMPTY) {
|
||||||
|
if (Math.random() < 0.6) {
|
||||||
|
maze[y][x] = DOT;
|
||||||
|
} else if (Math.random() < 0.3) {
|
||||||
|
maze[y][x] = WALL;
|
||||||
|
}
|
||||||
|
} else if (currentCell === DOT) {
|
||||||
|
if (Math.random() < 0.3) {
|
||||||
|
maze[y][x] = EMPTY;
|
||||||
|
} else if (Math.random() < 0.1) {
|
||||||
|
maze[y][x] = WALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let y = 1; y < ROWS - 1; y++) {
|
||||||
|
for (let x = 1; x < COLS - 1; x++) {
|
||||||
|
if (maze[y][x] === WALL) {
|
||||||
|
const neighbors = [
|
||||||
|
maze[y-1][x], maze[y+1][x], maze[y][x-1], maze[y][x+1]
|
||||||
|
];
|
||||||
|
const wallCount = neighbors.filter(c => c === WALL).length;
|
||||||
|
|
||||||
|
if (wallCount === 0 && Math.random() < 0.4) {
|
||||||
|
maze[y][x] = DOT;
|
||||||
|
} else if (wallCount === 4 && Math.random() < 0.3) {
|
||||||
|
maze[y][x] = EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Labyrinthe modifié aléatoirement');
|
||||||
|
}
|
||||||
|
|
||||||
|
function placeBonuses() {
|
||||||
|
bonuses = [];
|
||||||
|
const bonusPositions = [
|
||||||
|
{x: 1, y: 1, type: BONUS_CHERRY},
|
||||||
|
{x: 28, y: 1, type: BONUS_CHERRY},
|
||||||
|
{x: 1, y: 28, type: BONUS_CHERRY},
|
||||||
|
{x: 28, y: 28, type: BONUS_CHERRY},
|
||||||
|
{x: 14, y: 14, type: BONUS_LUDO},
|
||||||
|
{x: 15, y: 14, type: BONUS_LUDO}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let pos of bonusPositions) {
|
||||||
|
if (maze[pos.y][pos.x] === EMPTY || maze[pos.y][pos.x] === DOT) {
|
||||||
|
maze[pos.y][pos.x] = pos.type;
|
||||||
|
bonuses.push(new Bonus(pos.x, pos.y, pos.type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initGame() {
|
||||||
|
currentMazeIndex = 0;
|
||||||
|
originalMaze = mazeVariants[0];
|
||||||
|
maze = originalMaze.map(row => [...row]);
|
||||||
|
countDots();
|
||||||
|
score = 0;
|
||||||
|
level = 1;
|
||||||
|
cherriesEaten = 0;
|
||||||
|
scoreElement.textContent = score;
|
||||||
|
levelElement.textContent = level;
|
||||||
|
gameRunning = true;
|
||||||
|
statusElement.textContent = 'En jeu';
|
||||||
|
statusElement.style.color = '#ffd700';
|
||||||
|
restartBtn.style.display = 'none';
|
||||||
|
|
||||||
|
pacman = new Pacman();
|
||||||
|
ghosts[0] = new Ghost(14, 11, '#ff0000');
|
||||||
|
ghosts[1] = new Ghost(15, 11, '#ff00ff');
|
||||||
|
ghosts[2] = new Ghost(14, 12, '#00ffff');
|
||||||
|
ghosts[3] = new Ghost(15, 12, '#ffa500');
|
||||||
|
|
||||||
|
for (let ghost of ghosts) {
|
||||||
|
ghost.updateSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
placeBonuses();
|
||||||
|
countDots();
|
||||||
|
gameLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (!gameRunning) return;
|
||||||
|
|
||||||
|
switch(e.key) {
|
||||||
|
case 'ArrowUp':
|
||||||
|
pacman.nextDirection = 0;
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
case 'ArrowRight':
|
||||||
|
pacman.nextDirection = 1;
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
pacman.nextDirection = 2;
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
case 'ArrowLeft':
|
||||||
|
pacman.nextDirection = 3;
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function getScores() {
|
||||||
|
const scoresJson = localStorage.getItem('pacmanScores');
|
||||||
|
return scoresJson ? JSON.parse(scoresJson) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveScore() {
|
||||||
|
const username = usernameInput.value.trim() || 'Anonyme';
|
||||||
|
if (score > 0) {
|
||||||
|
const scores = getScores();
|
||||||
|
scores.push({
|
||||||
|
username: username,
|
||||||
|
score: score,
|
||||||
|
date: new Date().toISOString()
|
||||||
|
});
|
||||||
|
scores.sort((a, b) => b.score - a.score);
|
||||||
|
const topScores = scores.slice(0, 10);
|
||||||
|
localStorage.setItem('pacmanScores', JSON.stringify(topScores));
|
||||||
|
updateLeaderboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLeaderboard() {
|
||||||
|
const scores = getScores();
|
||||||
|
leaderboardElement.innerHTML = '';
|
||||||
|
|
||||||
|
if (scores.length === 0) {
|
||||||
|
leaderboardElement.innerHTML = '<div class="empty-leaderboard">Aucun score enregistré</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scores.forEach((entry, index) => {
|
||||||
|
const item = document.createElement('div');
|
||||||
|
item.className = 'leaderboard-item' + (index < 3 ? ' top' : '');
|
||||||
|
|
||||||
|
const rank = document.createElement('div');
|
||||||
|
rank.className = 'leaderboard-rank';
|
||||||
|
rank.textContent = (index + 1) + '.';
|
||||||
|
|
||||||
|
const name = document.createElement('div');
|
||||||
|
name.className = 'leaderboard-name';
|
||||||
|
name.textContent = entry.username;
|
||||||
|
|
||||||
|
const scoreDiv = document.createElement('div');
|
||||||
|
scoreDiv.className = 'leaderboard-score';
|
||||||
|
scoreDiv.textContent = entry.score;
|
||||||
|
|
||||||
|
item.appendChild(rank);
|
||||||
|
item.appendChild(name);
|
||||||
|
item.appendChild(scoreDiv);
|
||||||
|
leaderboardElement.appendChild(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
restartBtn.addEventListener('click', () => {
|
||||||
|
initGame();
|
||||||
|
});
|
||||||
|
|
||||||
|
updateLeaderboard();
|
||||||
|
initGame();
|
||||||
|
|
||||||
39
index.html
Normal file
39
index.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Jeu Pacman</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="main-wrapper">
|
||||||
|
<div class="container">
|
||||||
|
<h1>PACMAN</h1>
|
||||||
|
<div class="user-input-section">
|
||||||
|
<label for="username">Nom d'utilisateur:</label>
|
||||||
|
<input type="text" id="username" placeholder="Entrez votre nom" maxlength="15">
|
||||||
|
</div>
|
||||||
|
<div class="game-info">
|
||||||
|
<div class="score">Score: <span id="score">0</span></div>
|
||||||
|
<div class="level">Niveau: <span id="level">1</span></div>
|
||||||
|
<div class="status" id="status">Prêt à jouer</div>
|
||||||
|
</div>
|
||||||
|
<canvas id="gameCanvas" width="600" height="600"></canvas>
|
||||||
|
<div class="instructions">
|
||||||
|
<p>Utilisez les flèches directionnelles pour déplacer Pacman</p>
|
||||||
|
<button id="restartBtn" style="display: none;">Rejouer</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="leaderboard-container">
|
||||||
|
<h2>Classement</h2>
|
||||||
|
<div id="leaderboard"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
<p>By Ludo and Syoul</p>
|
||||||
|
</footer>
|
||||||
|
<script src="game.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
242
style.css
Normal file
242
style.css
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
|
||||||
|
color: #fff;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 30px;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
text-align: center;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3em;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.5);
|
||||||
|
color: #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 10px;
|
||||||
|
gap: 15px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gameCanvas {
|
||||||
|
border: 3px solid #ffd700;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #000;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-input-section {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-input-section label {
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#username {
|
||||||
|
padding: 8px 15px;
|
||||||
|
font-size: 1em;
|
||||||
|
border: 2px solid #ffd700;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
color: #fff;
|
||||||
|
outline: none;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#username:focus {
|
||||||
|
border-color: #ffed4e;
|
||||||
|
box-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.instructions {
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-container {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
padding: 25px;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||||||
|
min-width: 300px;
|
||||||
|
max-height: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-container h2 {
|
||||||
|
color: #ffd700;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 2em;
|
||||||
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#leaderboard {
|
||||||
|
max-height: 600px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-item {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-left: 4px solid #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-item.top {
|
||||||
|
background: rgba(255, 215, 0, 0.2);
|
||||||
|
border-left-color: #ffed4e;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-rank {
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffd700;
|
||||||
|
min-width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-name {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
margin-left: 15px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-score {
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffd700;
|
||||||
|
min-width: 80px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-leaderboard {
|
||||||
|
text-align: center;
|
||||||
|
color: #aaa;
|
||||||
|
padding: 20px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
#restartBtn {
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 12px 30px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
background: #ffd700;
|
||||||
|
color: #000;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#restartBtn:hover {
|
||||||
|
background: #ffed4e;
|
||||||
|
}
|
||||||
|
|
||||||
|
#restartBtn:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 20px;
|
||||||
|
color: #ffd700;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.main-wrapper {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaderboard-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
#gameCanvas {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-info {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-input-section {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user