From fedd606f154f7490c6d555eb04dd936be55d56e3 Mon Sep 17 00:00:00 2001 From: Hatmos Date: Sat, 1 Aug 2026 01:58:38 +0200 Subject: [PATCH] feat: add: boucle principale de jeu fonctionnelle --- client/index.html | 18 ++++++++- echoes.md | 79 ++++++++++++++++++++++++++++++++++++++++ server/package-lock.json | 1 + server/server.js | 39 +++++++++++++++++--- todo.md | 12 +++--- 5 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 echoes.md diff --git a/client/index.html b/client/index.html index f60bc22..e02102a 100644 --- a/client/index.html +++ b/client/index.html @@ -15,6 +15,12 @@ const socket = io(); let myRole = null; console.log("Connecte au serveur, id :", socket.id); + + socket.on("new_round", (startPos) => { + player.x = startPos.x; + player.y = startPos.y; + }); + socket.on("role", (role) => { console.log("Mon role :", role); myRole = role; @@ -87,6 +93,12 @@ drawPlayer(); } + function showGameOver(message){ + document.getElementById("gameOverMessage").textContent = message; + document.getElementById("gameOverScreen").style.display = "block"; + myRole = null; + } + document.addEventListener("keydown", (e) => { if (myRole !== "explorateur") return; @@ -114,9 +126,13 @@ if (result.correct){ console.log("Bonne porte ! Victoire (pour cette manche)."); } else { - console.log("Mauvaise porte. Partie terminee."); + showGameOver("Mauvaise porte. Vous avez perdu."); } }) + diff --git a/echoes.md b/echoes.md new file mode 100644 index 0000000..b2b10d2 --- /dev/null +++ b/echoes.md @@ -0,0 +1,79 @@ +# **Echoes** + +### *Jeu coopératif à deux joueurs* + +--- + +# Pitch + +**Echoes** est un jeu de coopération en ligne où deux joueurs doivent communiquer efficacement pour survivre. + +Chaque manche, les rôles sont répartis entre un **Guide** et un **Explorateur**. + +Le **Guide** est plongé dans l'obscurité. Il ne peut pas se déplacer, mais il est le seul à recevoir les instructions d'un mystérieux système de guidage. Il doit interpréter ces informations et les transmettre à son partenaire. + +L'**Explorateur**, quant à lui, voit le labyrinthe et peut s'y déplacer librement. Cependant, il ne reçoit aucune indication sur la bonne direction et dépend entièrement des informations fournies par le Guide. + +Ensemble, les deux joueurs doivent retrouver la bonne porte avant la fin du temps imparti. + +À chaque porte franchie avec succès, les rôles s'inversent : le Guide devient l'Explorateur, et inversement. Les joueurs devront alterner entre observation, communication et exploration jusqu'à atteindre le nombre de portes nécessaires pour remporter la partie. + +Le moindre mauvais choix est fatal : ouvrir une mauvaise porte met immédiatement fin à la partie. + +--- + +# Gameplay + +* Coopération à **2 joueurs**. +* Un joueur est **Guide**. +* Un joueur est **Explorateur**. +* Le Guide reçoit les indications mais ne peut pas se déplacer. +* L'Explorateur peut se déplacer mais ne connaît pas le chemin. +* Les joueurs doivent communiquer pour atteindre la bonne porte. +* Les rôles s'inversent après chaque porte correcte. +* Un chronomètre limite la durée de la partie. + +--- + +# Conditions de victoire + +* Trouver le nombre de portes demandé avant la fin du chronomètre. + +# Conditions de défaite + +* Ouvrir une mauvaise porte. +* Laisser le chronomètre atteindre zéro. + +--- + +# Objectifs du projet + +* Créer une expérience coopérative simple et accessible. +* Mettre la communication entre les joueurs au cœur du gameplay. +* Développer un prototype jouable rapidement, avec la possibilité d'ajouter de nouvelles fonctionnalités par la suite. + +--- + +# Évolutions possibles + +* Instructions vocales plutôt que textuelles. +* Dégradation progressive de la qualité des transmissions. +* Nouveaux labyrinthes. +* Pièges et fausses indications. +* Difficulté croissante. +* Classement basé sur le temps restant. + +--- + +# Technologies envisagées + +* **Frontend :** HTML, CSS, JavaScript +* **Backend :** Node.js + Socket.IO +* **Hébergement :** Serveur personnel +* **Plateforme :** Navigateur Web + +--- + +# Slogan + +**« Entendre ne suffit pas. Il faut aussi savoir se faire comprendre. »** diff --git a/server/package-lock.json b/server/package-lock.json index 3e5f625..c47818e 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -102,6 +102,7 @@ "version": "13.0.2", "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-13.0.2.tgz", "integrity": "sha512-jW6oufeDhXZaiX9Lw5A+oerVClx4iFrI6uDj1zu7SqUAjak9vbJvA0NEcKLNxHiQHb6kYCoFzzXYV0YOauhV3g==", + "hasInstallScript": true, "license": "MIT", "dependencies": { "node-addon-api": "^8.0.0" diff --git a/server/server.js b/server/server.js index d4cb703..6482513 100644 --- a/server/server.js +++ b/server/server.js @@ -27,19 +27,25 @@ io.on("connection", (socket) => { waitingPlayer = null; const socketIsGuide = Math.random() < 0.5; - socket.emit("role", socketIsGuide ? "guide" : "explorateur"); - partner.emit("role", socketIsGuide ? "explorateur" : "guide"); + const socketRole = socketIsGuide ? "guide" : "explorateur"; + const partnerRole = socketIsGuide ? "explorateur" : "guide"; socket.data.partnerId = partner.id; partner.data.partnerId = socket.id; + socket.emit("status", "Partie prete !"); + partner.emit("status", "Partie prete !"); + + socket.data.role = socketRole; + partner.data.role = partnerRole; + const pairState = { gameOver: false}; socket.data.pairState = pairState; partner.data.pairState = pairState; - socket.emit("status", "Partie prete !"); - partner.emit("status", "Partie prete !"); - } + socket.emit("role", socketRole); + partner.emit("role", partnerRole); +} socket.on("message", (data) => { const partnerId = socket.data.partnerId; @@ -53,15 +59,36 @@ io.on("connection", (socket) => { if (!pairState || pairState.gameOver) return; const partnerId = socket.data.partnerId; + const partnerSocket = io.sockets.sockets.get(partnerId); const isCorrect = position.x === correctDoor.x && position.y === correctDoor.y; if (!isCorrect){ pairState.gameOver = true; + const result = { correct: false}; + socket.emit("door_result", result); + if (partnerSocket) partnerSocket.emit("door_result", result); + return; } + const temp = socket.data.role; + socket.data.role = partnerSocket.data.role; + partnerSocket.data.role = temp; + + const startPos = { x: 1, y: 1}; + + console.log(pairState); const result = {correct: isCorrect}; - socket.emit("door_result", result); + socket.emit("door_result", { correct: true}); + socket.emit("new_round", startPos); + socket.emit("role", socket.data.role); + + if (partnerSocket){ + partnerSocket.emit("door_result", { correct: true }); + partnerSocket.emit("new_round", startPos); + partnerSocket.emit("role", partnerSocket.data.role); + } + if (partnerId){ io.to(partnerId).emit("door_result", result); } diff --git a/todo.md b/todo.md index fef2aa6..57f2ebf 100644 --- a/todo.md +++ b/todo.md @@ -1,6 +1,6 @@ -[ ] Randomizer les chemins -[ ] Donner les instructions via le son -[ ] Gerer une fin de niveau win/lose -[ ] Ajouter un compteur de niveau et un chronometre -[ ] Enregistrer les scores -[ ] Ajouter des instructions +-[] Randomizer les chemins +-[] Donner les instructions via le son +-[] Gerer une fin de niveau win/lose +-[] Ajouter un compteur de niveau et un chronometre +-[] Enregistrer les scores +-[] Ajouter des instructions