feat: add: boucle principale de jeu fonctionnelle
This commit is contained in:
@@ -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.");
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<div id="gameOverScreen" style="display: none;">
|
||||
<h2>Partie terminee</h2>
|
||||
<p id="gameOverMessage"></p>
|
||||
</div>
|
||||
</body>
|
||||
</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",
|
||||
"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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
12
todo.md
12
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
|
||||
|
||||
Reference in New Issue
Block a user