jeux html
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
# 🕹️ Rétro Arcade en HTML5 / JavaScript
|
||||||
|
|
||||||
|
Bienvenue dans ce dépôt de jeux d'arcade classiques entièrement développés en HTML5, CSS (Tailwind) et JavaScript pur (Vanilla JS). Aucun framework lourd ni installation complexe n'est requise : chaque jeu est contenu dans un unique fichier autonome.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Table des matières
|
||||||
|
|
||||||
|
1. [Pac-Man](#-pac-man)
|
||||||
|
2. [Breakout](#-breakout)
|
||||||
|
3. [Lancer les jeux](#-lancer-les-jeux)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟡 Pac-Man
|
||||||
|
|
||||||
|
Une adaptation moderne et fluide du célèbre jeu de labyrinthe arcade, optimisée pour le jeu directement dans le navigateur.
|
||||||
|
|
||||||
|
### Fonctionnalités :
|
||||||
|
|
||||||
|
- **Labyrinthe classique** avec gestion des pac-gommes et des scores en temps réel.
|
||||||
|
- **Système de Tunnels** fonctionnel sur les côtés pour traverser l'écran.
|
||||||
|
- **IA des fantômes** : déplacement intelligent aux intersections et évitement des blocages.
|
||||||
|
- **Commandes fluides** avec anticipation des virages pour un meilleur confort de jeu.
|
||||||
|
|
||||||
|
### Commandes :
|
||||||
|
|
||||||
|
- **Déplacement :** Touches fléchées `←` `↑` `↓` `→` ou les touches `Z` `Q` `S` `D`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧱 Breakout
|
||||||
|
|
||||||
|
\*_(Jeu classique de casse-briques)_
|
||||||
|
|
||||||
|
_(Section à compléter lors de l'ajout du code Breakout dans votre dépôt)_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Lancer les jeux
|
||||||
|
|
||||||
|
Aucun serveur ni installation de dépendances (comme Node.js) n'est nécessaire.
|
||||||
|
|
||||||
|
1. Téléchargez ou clonez les fichiers sur votre machine.
|
||||||
|
2. Ouvrez le fichier de votre choix (par exemple `pacman.html`) directement dans n'importe quel navigateur web moderne (**Google Chrome**, **Firefox**, **Edge**, etc.).
|
||||||
|
|
||||||
|
Bonne partie ! 🎮
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Casse-briques Agrandit</title>
|
||||||
|
<!-- Chargement de Tailwind CSS -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
</head>
|
||||||
|
<body
|
||||||
|
class="bg-slate-900 text-slate-100 flex flex-col items-center justify-center min-h-screen select-none"
|
||||||
|
>
|
||||||
|
<h1 class="text-3xl font-extrabold mb-4 tracking-wider text-amber-400">
|
||||||
|
CASSE-BRIQUES
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<!-- Conteneur du jeu élargi -->
|
||||||
|
<div
|
||||||
|
class="relative bg-slate-800 p-4 rounded-2xl shadow-2xl border border-slate-700"
|
||||||
|
>
|
||||||
|
<!-- Canvas plus grand (600x450) -->
|
||||||
|
<canvas
|
||||||
|
id="gameCanvas"
|
||||||
|
width="600"
|
||||||
|
height="450"
|
||||||
|
class="bg-slate-950 rounded-lg shadow-inner block"
|
||||||
|
></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-xs text-slate-400 mt-4">
|
||||||
|
Utilisez les touches fléchées **←** et **→** (ou **Q** et **D**) pour
|
||||||
|
déplacer la raquette.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById("gameCanvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// Paramètres de la balle
|
||||||
|
let x = canvas.width / 2;
|
||||||
|
let y = canvas.height - 40;
|
||||||
|
let dx = 3;
|
||||||
|
let dy = -3;
|
||||||
|
const ballRadius = 7;
|
||||||
|
|
||||||
|
// Paramètres de la raquette (élargie proportionnellement)
|
||||||
|
const paddleHeight = 12;
|
||||||
|
const paddleWidth = 90;
|
||||||
|
let paddleX = (canvas.width - paddleWidth) / 2;
|
||||||
|
|
||||||
|
// Contrôles
|
||||||
|
let rightPressed = false;
|
||||||
|
let leftPressed = false;
|
||||||
|
|
||||||
|
// Paramètres des briques (plus larges pour occuper l'espace de 600px)
|
||||||
|
const brickRowCount = 5;
|
||||||
|
const brickColumnCount = 8;
|
||||||
|
const brickWidth = 62;
|
||||||
|
const brickHeight = 22;
|
||||||
|
const brickPadding = 10;
|
||||||
|
const brickOffsetTop = 60; // Espace important entre le haut et les cibles
|
||||||
|
const brickOffsetLeft = 32;
|
||||||
|
|
||||||
|
let score = 0;
|
||||||
|
let lives = 3;
|
||||||
|
|
||||||
|
// Initialisation du tableau des briques
|
||||||
|
const bricks = [];
|
||||||
|
for (let c = 0; c < brickColumnCount; c++) {
|
||||||
|
bricks[c] = [];
|
||||||
|
for (let r = 0; r < brickRowCount; r++) {
|
||||||
|
bricks[c][r] = { x: 0, y: 0, status: 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Écouteurs d'événements clavier
|
||||||
|
document.addEventListener("keydown", keyDownHandler, false);
|
||||||
|
document.addEventListener("keyup", keyUpHandler, false);
|
||||||
|
|
||||||
|
function keyDownHandler(e) {
|
||||||
|
if (
|
||||||
|
e.key === "Right" ||
|
||||||
|
e.key === "ArrowRight" ||
|
||||||
|
e.key === "d" ||
|
||||||
|
e.key === "D"
|
||||||
|
) {
|
||||||
|
rightPressed = true;
|
||||||
|
} else if (
|
||||||
|
e.key === "Left" ||
|
||||||
|
e.key === "ArrowLeft" ||
|
||||||
|
e.key === "q" ||
|
||||||
|
e.key === "Q"
|
||||||
|
) {
|
||||||
|
leftPressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyUpHandler(e) {
|
||||||
|
if (
|
||||||
|
e.key === "Right" ||
|
||||||
|
e.key === "ArrowRight" ||
|
||||||
|
e.key === "d" ||
|
||||||
|
e.key === "D"
|
||||||
|
) {
|
||||||
|
rightPressed = false;
|
||||||
|
} else if (
|
||||||
|
e.key === "Left" ||
|
||||||
|
e.key === "ArrowLeft" ||
|
||||||
|
e.key === "q" ||
|
||||||
|
e.key === "Q"
|
||||||
|
) {
|
||||||
|
leftPressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Détection des collisions avec les briques
|
||||||
|
function collisionDetection() {
|
||||||
|
for (let c = 0; c < brickColumnCount; c++) {
|
||||||
|
for (let r = 0; r < brickRowCount; r++) {
|
||||||
|
const b = bricks[c][r];
|
||||||
|
if (b.status === 1) {
|
||||||
|
if (
|
||||||
|
x > b.x &&
|
||||||
|
x < b.x + brickWidth &&
|
||||||
|
y > b.y &&
|
||||||
|
y < b.y + brickHeight
|
||||||
|
) {
|
||||||
|
dy = -dy;
|
||||||
|
b.status = 0;
|
||||||
|
score += 10;
|
||||||
|
// Victoire
|
||||||
|
if (score === brickRowCount * brickColumnCount * 10) {
|
||||||
|
alert("VICTOIRE ! Félicitations !");
|
||||||
|
document.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dessiner la balle
|
||||||
|
function drawBall() {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = "#f43f5e";
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dessiner la raquette
|
||||||
|
function drawPaddle() {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(
|
||||||
|
paddleX,
|
||||||
|
canvas.height - paddleHeight - 15,
|
||||||
|
paddleWidth,
|
||||||
|
paddleHeight,
|
||||||
|
);
|
||||||
|
ctx.fillStyle = "#38bdf8";
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dessiner les briques
|
||||||
|
function drawBricks() {
|
||||||
|
const colors = ["#f59e0b", "#10b981", "#6366f1", "#ec4899", "#8b5cf6"];
|
||||||
|
for (let c = 0; c < brickColumnCount; c++) {
|
||||||
|
for (let r = 0; r < brickRowCount; r++) {
|
||||||
|
if (bricks[c][r].status === 1) {
|
||||||
|
const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
|
||||||
|
const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
|
||||||
|
bricks[c][r].x = brickX;
|
||||||
|
bricks[c][r].y = brickY;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(brickX, brickY, brickWidth, brickHeight);
|
||||||
|
ctx.fillStyle = colors[r % colors.length];
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Afficher le score et les vies
|
||||||
|
function drawScoreAndLives() {
|
||||||
|
ctx.font = "14px monospace";
|
||||||
|
ctx.fillStyle = "#94a3b8";
|
||||||
|
ctx.fillText("Score: " + score, 25, 30);
|
||||||
|
ctx.fillText("Vies: " + lives, canvas.width - 75, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boucle principale du jeu
|
||||||
|
function draw() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
drawBricks();
|
||||||
|
drawBall();
|
||||||
|
drawPaddle();
|
||||||
|
drawScoreAndLives();
|
||||||
|
collisionDetection();
|
||||||
|
|
||||||
|
// Rebond sur les murs (gauche / droite)
|
||||||
|
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
|
||||||
|
dx = -dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebond sur le mur du haut
|
||||||
|
if (y + dy < ballRadius) {
|
||||||
|
dy = -dy;
|
||||||
|
}
|
||||||
|
// Gestion de la raquette et du bas (perte de vie)
|
||||||
|
else if (y + dy > canvas.height - ballRadius - 15) {
|
||||||
|
if (x > paddleX && x < paddleX + paddleWidth) {
|
||||||
|
let hitPoint = x - (paddleX + paddleWidth / 2);
|
||||||
|
dx = hitPoint * 0.15;
|
||||||
|
dy = -dy;
|
||||||
|
} else {
|
||||||
|
lives--;
|
||||||
|
if (!lives) {
|
||||||
|
alert("GAME OVER");
|
||||||
|
document.location.reload();
|
||||||
|
} else {
|
||||||
|
x = canvas.width / 2;
|
||||||
|
y = canvas.height - 40;
|
||||||
|
dx = 3;
|
||||||
|
dy = -3;
|
||||||
|
paddleX = (canvas.width - paddleWidth) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouvement de la raquette
|
||||||
|
if (rightPressed && paddleX < canvas.width - paddleWidth) {
|
||||||
|
paddleX += 7;
|
||||||
|
} else if (leftPressed && paddleX > 0) {
|
||||||
|
paddleX -= 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouvement de la balle
|
||||||
|
x += dx;
|
||||||
|
y += dy;
|
||||||
|
|
||||||
|
requestAnimationFrame(draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lancement du jeu
|
||||||
|
draw();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Casse-briques Autonome</title>
|
||||||
|
<!-- Chargement de Tailwind CSS pour le design de la page -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
</head>
|
||||||
|
<body
|
||||||
|
class="bg-slate-900 text-slate-100 flex flex-col items-center justify-center min-h-screen select-none"
|
||||||
|
>
|
||||||
|
<h1 class="text-3xl font-extrabold mb-4 tracking-wider text-amber-400">
|
||||||
|
CASSE-BRIQUES
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<!-- Conteneur du jeu -->
|
||||||
|
<div
|
||||||
|
class="relative bg-slate-800 p-4 rounded-2xl shadow-2xl border border-slate-700"
|
||||||
|
>
|
||||||
|
<canvas
|
||||||
|
id="gameCanvas"
|
||||||
|
width="480"
|
||||||
|
height="320"
|
||||||
|
class="bg-slate-950 rounded-lg shadow-inner block"
|
||||||
|
></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-xs text-slate-400 mt-4">
|
||||||
|
Utilisez les touches fléchées **←** et **→** (ou **Q** et **D**) pour
|
||||||
|
déplacer la raquette.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById("gameCanvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// Paramètres de la balle
|
||||||
|
let x = canvas.width / 2;
|
||||||
|
let y = canvas.height - 30;
|
||||||
|
let dx = 2;
|
||||||
|
let dy = -2;
|
||||||
|
const ballRadius = 6;
|
||||||
|
|
||||||
|
// Paramètres de la raquette
|
||||||
|
const paddleHeight = 10;
|
||||||
|
const paddleWidth = 75;
|
||||||
|
let paddleX = (canvas.width - paddleWidth) / 2;
|
||||||
|
|
||||||
|
// Contrôles
|
||||||
|
let rightPressed = false;
|
||||||
|
let leftPressed = false;
|
||||||
|
|
||||||
|
// Paramètres des briques
|
||||||
|
const brickRowCount = 4;
|
||||||
|
const brickColumnCount = 7;
|
||||||
|
const brickWidth = 60;
|
||||||
|
const brickHeight = 20;
|
||||||
|
const brickPadding = 8;
|
||||||
|
const brickOffsetTop = 30;
|
||||||
|
const brickOffsetLeft = 18;
|
||||||
|
|
||||||
|
let score = 0;
|
||||||
|
let lives = 3;
|
||||||
|
|
||||||
|
// Initialisation du tableau des briques
|
||||||
|
const bricks = [];
|
||||||
|
for (let c = 0; c < brickColumnCount; c++) {
|
||||||
|
bricks[c] = [];
|
||||||
|
for (let r = 0; r < brickRowCount; r++) {
|
||||||
|
bricks[c][r] = { x: 0, y: 0, status: 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Écouteurs d'événements clavier
|
||||||
|
document.addEventListener("keydown", keyDownHandler, false);
|
||||||
|
document.addEventListener("keyup", keyUpHandler, false);
|
||||||
|
|
||||||
|
function keyDownHandler(e) {
|
||||||
|
if (
|
||||||
|
e.key === "Right" ||
|
||||||
|
e.key === "ArrowRight" ||
|
||||||
|
e.key === "d" ||
|
||||||
|
e.key === "D"
|
||||||
|
) {
|
||||||
|
rightPressed = true;
|
||||||
|
} else if (
|
||||||
|
e.key === "Left" ||
|
||||||
|
e.key === "ArrowLeft" ||
|
||||||
|
e.key === "q" ||
|
||||||
|
e.key === "Q"
|
||||||
|
) {
|
||||||
|
leftPressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyUpHandler(e) {
|
||||||
|
if (
|
||||||
|
e.key === "Right" ||
|
||||||
|
e.key === "ArrowRight" ||
|
||||||
|
e.key === "d" ||
|
||||||
|
e.key === "D"
|
||||||
|
) {
|
||||||
|
rightPressed = false;
|
||||||
|
} else if (
|
||||||
|
e.key === "Left" ||
|
||||||
|
e.key === "ArrowLeft" ||
|
||||||
|
e.key === "q" ||
|
||||||
|
e.key === "Q"
|
||||||
|
) {
|
||||||
|
leftPressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Détection des collisions avec les briques
|
||||||
|
function collisionDetection() {
|
||||||
|
for (let c = 0; c < brickColumnCount; c++) {
|
||||||
|
for (let r = 0; r < brickRowCount; r++) {
|
||||||
|
const b = bricks[c][r];
|
||||||
|
if (b.status === 1) {
|
||||||
|
if (
|
||||||
|
x > b.x &&
|
||||||
|
x < b.x + brickWidth &&
|
||||||
|
y > b.y &&
|
||||||
|
y < b.y + brickHeight
|
||||||
|
) {
|
||||||
|
dy = -dy;
|
||||||
|
b.status = 0;
|
||||||
|
score += 10;
|
||||||
|
// Victoire
|
||||||
|
if (score === brickRowCount * brickColumnCount * 10) {
|
||||||
|
alert("VICTOIRE ! Félicitations !");
|
||||||
|
document.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dessiner la balle
|
||||||
|
function drawBall() {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
|
||||||
|
ctx.fillStyle = "#f43f5e"; // Rouge vif
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dessiner la raquette
|
||||||
|
function drawPaddle() {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(
|
||||||
|
paddleX,
|
||||||
|
canvas.height - paddleHeight - 10,
|
||||||
|
paddleWidth,
|
||||||
|
paddleHeight,
|
||||||
|
);
|
||||||
|
ctx.fillStyle = "#38bdf8"; // Bleu clair
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dessiner les briques
|
||||||
|
function drawBricks() {
|
||||||
|
const colors = ["#f59e0b", "#10b981", "#6366f1", "#ec4899"]; // Couleurs par ligne
|
||||||
|
for (let c = 0; c < brickColumnCount; c++) {
|
||||||
|
for (let r = 0; r < brickRowCount; r++) {
|
||||||
|
if (bricks[c][r].status === 1) {
|
||||||
|
const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
|
||||||
|
const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
|
||||||
|
bricks[c][r].x = brickX;
|
||||||
|
bricks[c][r].y = brickY;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(brickX, brickY, brickWidth, brickHeight);
|
||||||
|
ctx.fillStyle = colors[r % colors.length];
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Afficher le score et les vies
|
||||||
|
function drawScoreAndLives() {
|
||||||
|
ctx.font = "12px monospace";
|
||||||
|
ctx.fillStyle = "#94a3b8";
|
||||||
|
ctx.fillText("Score: " + score, 20, 20);
|
||||||
|
ctx.fillText("Vies: " + lives, canvas.width - 60, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boucle principale du jeu
|
||||||
|
function draw() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
drawBricks();
|
||||||
|
drawBall();
|
||||||
|
drawPaddle();
|
||||||
|
drawScoreAndLives();
|
||||||
|
collisionDetection();
|
||||||
|
|
||||||
|
// Rebond sur les murs (gauche / droite)
|
||||||
|
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
|
||||||
|
dx = -dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebond sur le mur du haut
|
||||||
|
if (y + dy < ballRadius) {
|
||||||
|
dy = -dy;
|
||||||
|
}
|
||||||
|
// Gestion de la raquette et du bas (perte de vie)
|
||||||
|
else if (y + dy > canvas.height - ballRadius - 10) {
|
||||||
|
if (x > paddleX && x < paddleX + paddleWidth) {
|
||||||
|
// Effet d'angle selon l'endroit où la balle tape la raquette
|
||||||
|
let hitPoint = x - (paddleX + paddleWidth / 2);
|
||||||
|
dx = hitPoint * 0.15;
|
||||||
|
dy = -dy;
|
||||||
|
} else {
|
||||||
|
lives--;
|
||||||
|
if (!lives) {
|
||||||
|
alert("GAME OVER");
|
||||||
|
document.location.reload();
|
||||||
|
} else {
|
||||||
|
x = canvas.width / 2;
|
||||||
|
y = canvas.height - 30;
|
||||||
|
dx = 2;
|
||||||
|
dy = -2;
|
||||||
|
paddleX = (canvas.width - paddleWidth) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouvement de la raquette
|
||||||
|
if (rightPressed && paddleX < canvas.width - paddleWidth) {
|
||||||
|
paddleX += 6;
|
||||||
|
} else if (leftPressed && paddleX > 0) {
|
||||||
|
paddleX -= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouvement de la balle
|
||||||
|
x += dx;
|
||||||
|
y += dy;
|
||||||
|
|
||||||
|
requestAnimationFrame(draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lancement du jeu
|
||||||
|
draw();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+366
@@ -0,0 +1,366 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Pac-Man Grand Format - Contrôles Fluides</title>
|
||||||
|
<!-- Chargement de Tailwind CSS -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
</head>
|
||||||
|
<body
|
||||||
|
class="bg-slate-950 text-slate-100 flex flex-col items-center justify-center min-h-screen select-none"
|
||||||
|
>
|
||||||
|
<h1 class="text-3xl font-extrabold mb-3 tracking-widest text-yellow-400">
|
||||||
|
PAC-MAN
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<!-- Tableau de bord (Score / Vies) -->
|
||||||
|
<div
|
||||||
|
class="flex justify-between w-[800px] mb-2 px-2 font-mono text-base text-slate-300"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
Score : <span id="score" class="text-yellow-400 font-bold">0</span>
|
||||||
|
</div>
|
||||||
|
<div>Vies : <span id="lives" class="text-red-500 font-bold">3</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Conteneur du jeu (800x800) -->
|
||||||
|
<div
|
||||||
|
class="relative bg-black p-4 rounded-2xl shadow-2xl border-2 border-blue-600"
|
||||||
|
>
|
||||||
|
<canvas id="gameCanvas" width="800" height="800" class="block"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-xs text-slate-400 mt-4">
|
||||||
|
Utilisez les touches fléchées **← ↑ ↓ →** (ou **Z Q S D**) pour guider
|
||||||
|
Pac-Man.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById("gameCanvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
const tileSize = 40;
|
||||||
|
const speed = 4;
|
||||||
|
|
||||||
|
const map = [
|
||||||
|
[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, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1],
|
||||||
|
[1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1],
|
||||||
|
[1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1],
|
||||||
|
[1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1],
|
||||||
|
[1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1],
|
||||||
|
[1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1],
|
||||||
|
[1, 1, 1, 1, 2, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 2, 1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1, 2, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 2, 1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1, 2, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 2, 1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1],
|
||||||
|
[1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1],
|
||||||
|
[1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1],
|
||||||
|
[1, 2, 2, 1, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 1, 2, 2, 1],
|
||||||
|
[1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1],
|
||||||
|
[1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 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],
|
||||||
|
];
|
||||||
|
|
||||||
|
let score = 0;
|
||||||
|
let lives = 3;
|
||||||
|
|
||||||
|
let pacman = {
|
||||||
|
x: 9 * tileSize + tileSize / 2,
|
||||||
|
y: 16 * tileSize + tileSize / 2,
|
||||||
|
radius: tileSize / 2 - 4,
|
||||||
|
dx: 0,
|
||||||
|
dy: 0,
|
||||||
|
nextDx: 0,
|
||||||
|
nextDy: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ghosts = [
|
||||||
|
{
|
||||||
|
x: 9 * tileSize + tileSize / 2,
|
||||||
|
y: 9 * tileSize + tileSize / 2,
|
||||||
|
color: "#ef4444",
|
||||||
|
dx: speed,
|
||||||
|
dy: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 10 * tileSize + tileSize / 2,
|
||||||
|
y: 9 * tileSize + tileSize / 2,
|
||||||
|
color: "#ec4899",
|
||||||
|
dx: -speed,
|
||||||
|
dy: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 9 * tileSize + tileSize / 2,
|
||||||
|
y: 10 * tileSize + tileSize / 2,
|
||||||
|
color: "#06b6d4",
|
||||||
|
dx: 0,
|
||||||
|
dy: -speed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 10 * tileSize + tileSize / 2,
|
||||||
|
y: 10 * tileSize + tileSize / 2,
|
||||||
|
color: "#f97316",
|
||||||
|
dx: 0,
|
||||||
|
dy: speed,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
window.addEventListener("keydown", (e) => {
|
||||||
|
switch (e.key) {
|
||||||
|
case "ArrowLeft":
|
||||||
|
case "q":
|
||||||
|
case "Q":
|
||||||
|
pacman.nextDx = -speed;
|
||||||
|
pacman.nextDy = 0;
|
||||||
|
break;
|
||||||
|
case "ArrowRight":
|
||||||
|
case "d":
|
||||||
|
case "D":
|
||||||
|
pacman.nextDx = speed;
|
||||||
|
pacman.nextDy = 0;
|
||||||
|
break;
|
||||||
|
case "ArrowUp":
|
||||||
|
case "z":
|
||||||
|
case "Z":
|
||||||
|
pacman.nextDx = 0;
|
||||||
|
pacman.nextDy = -speed;
|
||||||
|
break;
|
||||||
|
case "ArrowDown":
|
||||||
|
case "s":
|
||||||
|
case "S":
|
||||||
|
pacman.nextDx = 0;
|
||||||
|
pacman.nextDy = speed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function isWall(pixelX, pixelY) {
|
||||||
|
let c = Math.floor(pixelX / tileSize);
|
||||||
|
let r = Math.floor(pixelY / tileSize);
|
||||||
|
if (r === 8 || r === 10 || r === 12) {
|
||||||
|
if (pixelX < 0 || pixelX >= canvas.width) return false;
|
||||||
|
}
|
||||||
|
if (r < 0 || r >= map.length || c < 0 || c >= map[0].length)
|
||||||
|
return true;
|
||||||
|
return map[r][c] === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCollisionBox(x, y, radius) {
|
||||||
|
const corners = [
|
||||||
|
{ x: x - radius, y: y - radius },
|
||||||
|
{ x: x + radius, y: y - radius },
|
||||||
|
{ x: x - radius, y: y + radius },
|
||||||
|
{ x: x + radius, y: y + radius },
|
||||||
|
];
|
||||||
|
for (let corner of corners) {
|
||||||
|
if (isWall(corner.x, corner.y)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAtIntersection(x, y) {
|
||||||
|
return (
|
||||||
|
(x - tileSize / 2) % tileSize === 0 &&
|
||||||
|
(y - tileSize / 2) % tileSize === 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
if (pacman.x < -tileSize / 2) {
|
||||||
|
pacman.x = canvas.width + tileSize / 2;
|
||||||
|
} else if (pacman.x > canvas.width + tileSize / 2) {
|
||||||
|
pacman.x = -tileSize / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changement de direction immédiat si la voie est libre dans la nouvelle direction désirée
|
||||||
|
if (pacman.nextDx !== 0 || pacman.nextDy !== 0) {
|
||||||
|
// Demi-tour instantané autorisé
|
||||||
|
if (pacman.nextDx === -pacman.dx && pacman.nextDy === -pacman.dy) {
|
||||||
|
pacman.dx = pacman.nextDx;
|
||||||
|
pacman.dy = pacman.nextDy;
|
||||||
|
}
|
||||||
|
// Changement normal si on passe par une intersection ou si l'axe change proprement
|
||||||
|
else if (
|
||||||
|
!checkCollisionBox(
|
||||||
|
pacman.x + pacman.nextDx,
|
||||||
|
pacman.y + pacman.nextDy,
|
||||||
|
pacman.radius,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Si on change d'axe (ex: on va verticalement et on veut aller horizontalement), on s'assure d'être aligné sur la grille
|
||||||
|
if (
|
||||||
|
(pacman.dx !== 0 && pacman.nextDy !== 0) ||
|
||||||
|
(pacman.dy !== 0 && pacman.nextDx !== 0)
|
||||||
|
) {
|
||||||
|
if (isAtIntersection(pacman.x, pacman.y)) {
|
||||||
|
pacman.dx = pacman.nextDx;
|
||||||
|
pacman.dy = pacman.nextDy;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pacman.dx = pacman.nextDx;
|
||||||
|
pacman.dy = pacman.nextDy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avancer Pac-Man s'il n'y a pas de mur devant lui
|
||||||
|
if (
|
||||||
|
!checkCollisionBox(
|
||||||
|
pacman.x + pacman.dx,
|
||||||
|
pacman.y + pacman.dy,
|
||||||
|
pacman.radius,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
pacman.x += pacman.dx;
|
||||||
|
pacman.y += pacman.dy;
|
||||||
|
} else {
|
||||||
|
pacman.dx = 0;
|
||||||
|
pacman.dy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let gridX = Math.floor(pacman.x / tileSize);
|
||||||
|
let gridY = Math.floor(pacman.y / tileSize);
|
||||||
|
if (
|
||||||
|
gridY >= 0 &&
|
||||||
|
gridY < map.length &&
|
||||||
|
gridX >= 0 &&
|
||||||
|
gridX < map[0].length
|
||||||
|
) {
|
||||||
|
if (map[gridY][gridX] === 2) {
|
||||||
|
map[gridY][gridX] = 0;
|
||||||
|
score += 10;
|
||||||
|
document.getElementById("score").innerText = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ghosts.forEach((ghost) => {
|
||||||
|
if (ghost.x < -tileSize / 2) ghost.x = canvas.width + tileSize / 2;
|
||||||
|
if (ghost.x > canvas.width + tileSize / 2) ghost.x = -tileSize / 2;
|
||||||
|
|
||||||
|
if (isAtIntersection(ghost.x, ghost.y)) {
|
||||||
|
const possibleDirs = [
|
||||||
|
{ dx: speed, dy: 0 },
|
||||||
|
{ dx: -speed, dy: 0 },
|
||||||
|
{ dx: 0, dy: speed },
|
||||||
|
{ dx: 0, dy: -speed },
|
||||||
|
];
|
||||||
|
|
||||||
|
const oppositeDx = -ghost.dx;
|
||||||
|
const oppositeDy = -ghost.dy;
|
||||||
|
|
||||||
|
let validDirs = possibleDirs.filter((d) => {
|
||||||
|
if (d.dx === oppositeDx && d.dy === oppositeDy) return false;
|
||||||
|
let nextX = ghost.x + d.dx * 4;
|
||||||
|
let nextY = ghost.y + d.dy * 4;
|
||||||
|
return !checkCollisionBox(nextX, nextY, tileSize / 2 - 4);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (validDirs.length === 0) {
|
||||||
|
validDirs = [{ dx: oppositeDx, dy: oppositeDy }];
|
||||||
|
}
|
||||||
|
|
||||||
|
let chosen =
|
||||||
|
validDirs[Math.floor(Math.random() * validDirs.length)];
|
||||||
|
ghost.dx = chosen.dx;
|
||||||
|
ghost.dy = chosen.dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
checkCollisionBox(
|
||||||
|
ghost.x + ghost.dx,
|
||||||
|
ghost.y + ghost.dy,
|
||||||
|
tileSize / 2 - 4,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
ghost.dx = -ghost.dx;
|
||||||
|
ghost.dy = -ghost.dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
ghost.x += ghost.dx;
|
||||||
|
ghost.y += ghost.dy;
|
||||||
|
|
||||||
|
let dist = Math.hypot(pacman.x - ghost.x, pacman.y - ghost.y);
|
||||||
|
if (dist < tileSize / 2) {
|
||||||
|
lives--;
|
||||||
|
document.getElementById("lives").innerText = lives;
|
||||||
|
if (lives <= 0) {
|
||||||
|
alert("GAME OVER ! Score final : " + score);
|
||||||
|
document.location.reload();
|
||||||
|
} else {
|
||||||
|
pacman.x = 9 * tileSize + tileSize / 2;
|
||||||
|
pacman.y = 16 * tileSize + tileSize / 2;
|
||||||
|
pacman.dx = 0;
|
||||||
|
pacman.dy = 0;
|
||||||
|
pacman.nextDx = 0;
|
||||||
|
pacman.nextDy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
for (let r = 0; r < map.length; r++) {
|
||||||
|
for (let c = 0; c < map[r].length; c++) {
|
||||||
|
if (map[r][c] === 1) {
|
||||||
|
ctx.fillStyle = "#2563eb";
|
||||||
|
ctx.fillRect(c * tileSize, r * tileSize, tileSize, tileSize);
|
||||||
|
} else if (map[r][c] === 2) {
|
||||||
|
ctx.fillStyle = "#fde047";
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(
|
||||||
|
c * tileSize + tileSize / 2,
|
||||||
|
r * tileSize + tileSize / 2,
|
||||||
|
6,
|
||||||
|
0,
|
||||||
|
Math.PI * 2,
|
||||||
|
);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.fillStyle = "#facc15";
|
||||||
|
ctx.beginPath();
|
||||||
|
let angle = 0.2;
|
||||||
|
if (pacman.dx > 0) angle = 0.2;
|
||||||
|
if (pacman.dx < 0) angle = 1.2;
|
||||||
|
if (pacman.dy > 0) angle = 0.7;
|
||||||
|
if (pacman.dy < 0) angle = 1.7;
|
||||||
|
|
||||||
|
ctx.arc(
|
||||||
|
pacman.x,
|
||||||
|
pacman.y,
|
||||||
|
pacman.radius,
|
||||||
|
angle * Math.PI,
|
||||||
|
(angle + 1.6) * Math.PI,
|
||||||
|
);
|
||||||
|
ctx.lineTo(pacman.x, pacman.y);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ghosts.forEach((ghost) => {
|
||||||
|
ctx.fillStyle = ghost.color;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(ghost.x, ghost.y - 4, tileSize / 2 - 4, Math.PI, 0, false);
|
||||||
|
ctx.lineTo(ghost.x + tileSize / 2 - 4, ghost.y + tileSize / 2);
|
||||||
|
ctx.lineTo(ghost.x - tileSize / 2 + 4, ghost.y + tileSize / 2);
|
||||||
|
ctx.fill();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loop() {
|
||||||
|
update();
|
||||||
|
draw();
|
||||||
|
setTimeout(loop, 1000 / 45);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user