feat: add: boucle principale de jeu fonctionnelle
This commit is contained in:
@@ -15,6 +15,12 @@
|
|||||||
const socket = io();
|
const socket = io();
|
||||||
let myRole = null;
|
let myRole = null;
|
||||||
console.log("Connecte au serveur, id :", socket.id);
|
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) => {
|
socket.on("role", (role) => {
|
||||||
console.log("Mon role :", role);
|
console.log("Mon role :", role);
|
||||||
myRole = role;
|
myRole = role;
|
||||||
@@ -87,6 +93,12 @@
|
|||||||
drawPlayer();
|
drawPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showGameOver(message){
|
||||||
|
document.getElementById("gameOverMessage").textContent = message;
|
||||||
|
document.getElementById("gameOverScreen").style.display = "block";
|
||||||
|
myRole = null;
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("keydown", (e) => {
|
document.addEventListener("keydown", (e) => {
|
||||||
if (myRole !== "explorateur") return;
|
if (myRole !== "explorateur") return;
|
||||||
|
|
||||||
@@ -114,9 +126,13 @@
|
|||||||
if (result.correct){
|
if (result.correct){
|
||||||
console.log("Bonne porte ! Victoire (pour cette manche).");
|
console.log("Bonne porte ! Victoire (pour cette manche).");
|
||||||
} else {
|
} else {
|
||||||
console.log("Mauvaise porte. Partie terminee.");
|
showGameOver("Mauvaise porte. Vous avez perdu.");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
<div id="gameOverScreen" style="display: none;">
|
||||||
|
<h2>Partie terminee</h2>
|
||||||
|
<p id="gameOverMessage"></p>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
79
echoes.md
Normal file
79
echoes.md
Normal file
@@ -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. »**
|
||||||
1
server/package-lock.json
generated
1
server/package-lock.json
generated
@@ -102,6 +102,7 @@
|
|||||||
"version": "13.0.2",
|
"version": "13.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-13.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-13.0.2.tgz",
|
||||||
"integrity": "sha512-jW6oufeDhXZaiX9Lw5A+oerVClx4iFrI6uDj1zu7SqUAjak9vbJvA0NEcKLNxHiQHb6kYCoFzzXYV0YOauhV3g==",
|
"integrity": "sha512-jW6oufeDhXZaiX9Lw5A+oerVClx4iFrI6uDj1zu7SqUAjak9vbJvA0NEcKLNxHiQHb6kYCoFzzXYV0YOauhV3g==",
|
||||||
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-addon-api": "^8.0.0"
|
"node-addon-api": "^8.0.0"
|
||||||
|
|||||||
@@ -27,18 +27,24 @@ io.on("connection", (socket) => {
|
|||||||
waitingPlayer = null;
|
waitingPlayer = null;
|
||||||
|
|
||||||
const socketIsGuide = Math.random() < 0.5;
|
const socketIsGuide = Math.random() < 0.5;
|
||||||
socket.emit("role", socketIsGuide ? "guide" : "explorateur");
|
const socketRole = socketIsGuide ? "guide" : "explorateur";
|
||||||
partner.emit("role", socketIsGuide ? "explorateur" : "guide");
|
const partnerRole = socketIsGuide ? "explorateur" : "guide";
|
||||||
|
|
||||||
socket.data.partnerId = partner.id;
|
socket.data.partnerId = partner.id;
|
||||||
partner.data.partnerId = socket.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};
|
const pairState = { gameOver: false};
|
||||||
socket.data.pairState = pairState;
|
socket.data.pairState = pairState;
|
||||||
partner.data.pairState = pairState;
|
partner.data.pairState = pairState;
|
||||||
|
|
||||||
socket.emit("status", "Partie prete !");
|
socket.emit("role", socketRole);
|
||||||
partner.emit("status", "Partie prete !");
|
partner.emit("role", partnerRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.on("message", (data) => {
|
socket.on("message", (data) => {
|
||||||
@@ -53,15 +59,36 @@ io.on("connection", (socket) => {
|
|||||||
if (!pairState || pairState.gameOver) return;
|
if (!pairState || pairState.gameOver) return;
|
||||||
|
|
||||||
const partnerId = socket.data.partnerId;
|
const partnerId = socket.data.partnerId;
|
||||||
|
const partnerSocket = io.sockets.sockets.get(partnerId);
|
||||||
const isCorrect = position.x === correctDoor.x && position.y === correctDoor.y;
|
const isCorrect = position.x === correctDoor.x && position.y === correctDoor.y;
|
||||||
|
|
||||||
if (!isCorrect){
|
if (!isCorrect){
|
||||||
pairState.gameOver = true;
|
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};
|
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){
|
if (partnerId){
|
||||||
io.to(partnerId).emit("door_result", result);
|
io.to(partnerId).emit("door_result", result);
|
||||||
}
|
}
|
||||||
|
|||||||
12
todo.md
12
todo.md
@@ -1,6 +1,6 @@
|
|||||||
[ ] Randomizer les chemins
|
-[] Randomizer les chemins
|
||||||
[ ] Donner les instructions via le son
|
-[] Donner les instructions via le son
|
||||||
[ ] Gerer une fin de niveau win/lose
|
-[] Gerer une fin de niveau win/lose
|
||||||
[ ] Ajouter un compteur de niveau et un chronometre
|
-[] Ajouter un compteur de niveau et un chronometre
|
||||||
[ ] Enregistrer les scores
|
-[] Enregistrer les scores
|
||||||
[ ] Ajouter des instructions
|
-[] Ajouter des instructions
|
||||||
|
|||||||
Reference in New Issue
Block a user