- Vue 44.5%
- PHP 29.4%
- TypeScript 25.2%
- CSS 0.5%
- Shell 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| docker | ||
| public/modeles | ||
| scripts | ||
| server | ||
| src | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| doc-tech.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| index.html | ||
| package.json | ||
| pnpm-lock.yaml | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
Bataille navale 3D
Squelette pédagogique : Vue 3 + BabylonLite (WebGPU) côté navigateur, serveur PHP + MariaDB pour arbitrer les parties.
Démarrage
pnpm install
pnpm serveur # API PHP (port 8000) + WebSocket (port 8001), dans un premier terminal
pnpm dev # http://localhost:5173 (dans un second terminal ; /api est proxifié vers le PHP)
Le serveur demande PHP 8.3+ avec l'extension pdo_mysql et un serveur MariaDB (10.6+).
pnpm serveur prend le premier binaire PHP qui a l'extension ($PHP, php, puis php8.5, php8.4, php8.3)
et affiche une erreur claire s'il n'en trouve aucun. Sous Ubuntu : sudo apt install mariadb-server php8.X-mysql.
Base de développement, à créer une fois (base navale, utilisateur et mot de passe navale) :
sudo mariadb < scripts/base-locale.sql
Les tables sont créées automatiquement au premier appel. Pour une autre base, définir les variables
NAVALE_BD_HOTE, NAVALE_BD_PORT (ou NAVALE_BD_SOCKET), NAVALE_BD_NOM, NAVALE_BD_UTILISATEUR et
NAVALE_BD_MOT_DE_PASSE (voir server/src/Base.php).
Ancienne base SQLite (server/data/navale.sqlite) : php server/migrer-sqlite.php [--vider] la copie dans MariaDB
(il faut aussi pdo_sqlite ; la base SQLite n'est pas modifiée).
Il faut un navigateur avec WebGPU (Chrome / Edge 113+, ou Firefox / Safari récents). Sans WebGPU, les grilles affichent un message d'erreur au lieu de la scène 3D.
Autres commandes :
pnpm typecheck # vérification TypeScript + Vue
pnpm check:picking # vérifie, sans GPU, la conversion pointeur → case
pnpm check:regles # compare les règles du client (rules.ts) et du serveur (Regles.php) sur des milliers de cas
pnpm build
La version de @babylonjs/lite est volontairement figée (1.34.0) : l'API évolue vite.
Jouer depuis le réseau local (HTTPS)
WebGPU n'est disponible que dans un contexte sécurisé : https://, ou http://localhost. Pour jouer depuis
un autre appareil du réseau local, il faut donc du HTTPS :
pnpm certificat # une fois (et à relancer si l'adresse IP change)
pnpm serveur # API PHP + WebSocket, écoutent seulement sur 127.0.0.1
pnpm dev:reseau # Vite en https sur toutes les interfaces : https://<ip-de-la-machine>:5173/
pnpm certificat crée dans certs/ (ignoré par git) une autorité de développement et un certificat signé par
elle, valable pour localhost et toutes les adresses IPv4 de la machine. Vite passe automatiquement en HTTPS dès
que ce certificat existe (y compris pnpm dev) ; /api et /ws (devenu wss://) restent relayés vers le PHP local.
Sur chaque appareil qui joue, installer une fois certs/autorite.crt comme autorité de confiance
(Chrome/Edge : Paramètres › Confidentialité et sécurité › Sécurité › Gérer les certificats › Autorités ;
Firefox : Paramètres › Vie privée › Certificats › Autorités ; Android/iOS : installer le fichier puis l'activer).
Sans cela, le navigateur affiche un avertissement qu'il faut accepter manuellement.
Ne jamais partager certs/autorite.key.
Architecture
src/
├─ game/ logique pure (aucune dépendance à Vue ni à Babylon)
│ ├─ types.ts constantes, CellState, Ship, flotte
│ └─ rules.ts placement valide ? résultat d'un tir ? partie finie ?
├─ engine/ tout ce qui touche à BabylonLite (aucune dépendance à Vue)
│ ├─ boardGeometry.ts case ↔ position dans le monde 3D
│ ├─ cellPicking.ts pointeur → case (rayon ∩ plan de la mer)
│ └─ boardScene.ts createBoardScene(canvas, options) → petite API
├─ components/ Vue : enveloppes fines autour du moteur
│ ├─ BoardView3D.vue une grille 3D (utilisée deux fois en jeu)
│ └─ ShipPlacement.vue placement des bateaux, vue de dessus
├─ api/client.ts appels au serveur PHP
└─ App.vue phases du jeu, synchronisation avec le serveur, animations des tirs
server/
├─ public/index.php point d'entrée unique de l'API (routeur)
├─ websocket.php serveur WebSocket : pousse l'état des parties en temps réel
├─ src/Regles.php traduction de game/rules.ts (le serveur valide tout)
├─ src/Parties.php création de partie, tirs, vue d'une partie pour un joueur
├─ src/JoueurFictif.php adversaire de développement
├─ src/Base.php connexion MariaDB + schéma (parties, joueurs, tirs…)
├─ migrer-sqlite.php import d'une ancienne base SQLite
└─ data/ ancienne base SQLite, le cas échéant (ignorée par git)
Canards en plastique
Chaque joueur peut poser de 0 à 2 canards en plastique (une case chacun, canard_1, canard_2). Un canard
protège les 3×3 cases autour de lui des explosions : explosion de pigeon, salve et torpille sautent ces cases
(elles restent à viser). Les tirs individuels ne sont pas affectés : un tir sur le canard le détruit
(« coulé ») et supprime sa protection. Les canards ne comptent pas pour la victoire. Le joueur fictif en pose 2.
Événements aléatoires
Après chaque tir individuel (le vôtre ou celui de l'adversaire), il y a 5 % de chances
(Parties::PROBABILITE_EVENEMENT) qu'un événement frappe les deux grilles :
| Événement | Effet sur chaque grille |
|---|---|
| ⛈ Tempête | 3 éclairs sur des cases au hasard |
| 🌋 Séisme | une zone 3×3 au hasard s'effondre |
| 🌊 Raz-de-marée | une colonne entière au hasard est balayée |
| 🐙 Kraken | une case du plus grand bateau encore à flot est frappée |
| 🐋 Baleine | elle traverse les deux grilles le long d'une même ligne au hasard et percute toutes les cases occupées (bateaux, pigeons, canards) encore intactes |
| 🧊 Iceberg | il percute une case (un bateau une fois sur deux, sinon de l'eau ; jamais un pigeon ni un canard). Le bateau heurté coule entièrement après 2 tours de son propriétaire (Parties::TOURS_AVANT_NAUFRAGE), c'est-à-dire quand celui-ci a fini de jouer deux fois ; un bandeau prévient le joueur. Les cases du naufrage sont des tirs evenement: 'naufrage' |
Les événements tirés dépendent de la carte (Parties::EVENEMENTS_PAR_CARTE, avec des poids), et l'interface les
habille selon elle (descriptionEvenement dans src/game/cartes.ts) :
| Carte | Événements (les plus fréquents en gras) |
|---|---|
| 🏝 Plage | tempête, raz-de-marée, kraken, baleine |
| 🧊 Banquise | blizzard (tempête), iceberg, baleine boréale |
| ⚓ Port | tempête, raz-de-marée, kraken |
| 🌋 Volcan | éruption (4 bombes de lave au hasard), séisme volcanique, tsunami (raz-de-marée) |
| ☁️ Nuages | orage (tempête), tornade (une ligne entière balayée) |
| 🌊 Abysses | kraken des abysses, cachalot (baleine), courant des abysses (raz-de-marée), séisme sous-marin |
Sur le volcan, la grille n'est pas de l'eau mais une mer de lave (croûte sombre, lave orange, veines incandescentes, ondulation lente).
Chaque carte ne garde que les événements cohérents avec son décor : pas de séisme ni de vague dans les airs, pas d'iceberg hors des eaux polaires, pas d'orage au fond de l'océan.
Le mode dev déclenche n'importe quel événement sur n'importe quelle carte.
Chaque case frappée compte comme un tir de l'adversaire du propriétaire de la grille (champ evenement du tir) :
pigeons touchés qui explosent, bateaux coulés et victoire compris. Le tour ne change pas. Les canards ne protègent
pas (ce ne sont pas des explosions). Le mode dev permet de déclencher chaque événement (action evenement, { type }).
Rejouer après une touche
Un tir qui touche un bateau ou un pigeon sans le couler permet de rejouer. La main passe à l'adversaire dès qu'on tire à l'eau ou qu'on coule une cible. Les bonus comptent toujours pour un seul coup (ils passent la main quel que soit leur résultat). La règle vaut aussi pour le joueur fictif.
Pigeons de combat
En plus des 5 bateaux, chaque joueur peut poser de 0 à 3 pigeons de combat (une case chacun,
identifiants pigeon_1 à pigeon_3). Ils se coulent en un tir et comptent pour la victoire.
Le joueur fictif en pose toujours 3. Ils sont dessinés en primitives (en vol, ailes battantes).
Pigeon kamikaze : un pigeon touché s'envole vers la grille de celui qui l'a abattu, se pose sur une case
que son propriétaire n'a pas encore visée, jamais au bord (la zone 3×3 est toujours entière dans la grille,
et de préférence sans case déjà visée), puis explose. Ces 9 tirs comptent pour le propriétaire du pigeon.
Si l'explosion touche un pigeon adverse, celui-ci repart à son tour : les réactions en chaîne sont possibles,
et un pigeon peut faire gagner son camp pendant le tour adverse. Chaque tir enregistre le pigeon à l'origine
(pigeon, centre) et un ordre global, pour que le client rejoue les animations dans l'ordre.
Progression : niveaux et succès
Chaque compte joueur gagne de l'expérience (XP) à chaque partie terminée avec un vainqueur, contre le joueur fictif comme en ligne :
| Résultat | XP |
|---|---|
| Victoire contre le joueur fictif | 60 (facile), 100 (moyen), 160 (difficile) |
| Victoire en ligne | 180 |
| Défaite | 25 |
| Chaque case touchée | +2 |
| Chaque succès débloqué | +50 |
Le niveau n demande 50 × n × (n − 1) XP au total (niveau 2 : 100, 3 : 300, 4 : 600…), avec un grade (Mousse, Matelot,
Quartier-maître… jusqu'à Amiral au niveau 30), dans la limite du niveau 999 (Progression::NIVEAU_MAX, l'XP continue de s'accumuler au-delà). Il y a 17 succès : première victoire, série de victoires, victoire sans
perte, précision ≥ 60 %, victoire en 45 tirs ou moins, toutes les cartes jouées, etc. (Progression::SUCCES).
Le niveau s'affiche dans l'en-tête (un clic ouvre « Ma progression » : statistiques et succès) et à côté du pseudo de
l'adversaire. La fenêtre de fin de partie indique l'XP gagnée et les succès débloqués. Les parties comptabilisées sont
gardées dans progression_parties, qui survit à la purge des parties. Les parties où le mode dev a servi (actions dev,
parties de test) ne rapportent rien.
Dans l'espace développeur, l'onglet Joueurs affiche le niveau, l'XP et le nombre de succès de chaque compte ; le bouton
Progression déplie le détail (statistiques, succès, ajustements, dernières parties comptabilisées). Les administrateurs
peuvent y ajouter ou retirer de l'XP avec un motif (progression_ajustements), débloquer ou retirer un succès et remettre
la progression à zéro, ou fixer directement le niveau (de 1 à 999 ; l'XP est ajustée au début du niveau choisi) ; chaque action est
inscrite dans l'audit.
Classement : les joueurs sont classés par XP (puis victoires). Il se consulte depuis « Ma progression » (onglet Classement), où chaque joueur choisit de figurer ou non dans le classement public (oui par défaut). L'onglet Joueurs de l'espace développeur affiche le classement complet, comptes cachés compris (grisés).
Bonus
Chaque joueur dispose de trois bonus, trois exemplaires de chacun (Parties::STOCK_BONUS_INITIAL), sauf exceptions indiquées, utilisables à la place d'un tir :
| Bonus | Effet |
|---|---|
| Salve | tir en croix : la case visée et ses 4 voisines |
| Torpille (2 exemplaires) | tire sur toute la ligne ou toute la colonne visée (les cases déjà visées sont ignorées) ; le sens se change avec les boutons Ligne / Colonne, la touche R ou un clic droit |
| Sonar | indique combien de cases occupées (non touchées) contient la zone 3×3 visée, sans tirer |
| Lancer de pain | révèle les pigeons ennemis (encore en vol) dans la zone 3×3 visée, sans tirer ; ils restent visibles |
| Trou noir (1 seul exemplaire) | zone de 3×2 (3 colonnes, la ligne visée et celle du dessous) : aspire les pigeons et canards ennemis (détruits, et les pigeons n'explosent pas) et touche les cases de bateaux ennemis ; les cases vides ne sont pas tirées |
| Super pigeon (1 seul exemplaire) | ajoute un pigeon à votre flotte, sur la case libre la plus éloignée des tirs adverses (jamais une case déjà tentée) ; touché, il explose en 5×5 chez l'adversaire. Pas de cible à choisir |
On clique sur le bonus (il s'« arme »), la zone concernée s'affiche au survol, puis on clique sur la grille. Le joueur fictif n'utilise pas de bonus.
Mode dev
Avec pnpm dev, un bouton DEV (en bas à droite, ou Ctrl+Maj+D) ouvre un panneau de débogage :
identifiant de partie (copiable), version, tour, état du WebSocket, tirs et bonus restants, et les actions :
Action (/dev/...) |
Effet |
|---|---|
flotte-adverse |
révèle (ou masque) toute la flotte adverse sur sa grille |
tout-exploser |
tire sur toutes les cases adverses restantes : victoire (à son tour) |
defaite |
l'adversaire tire sur toutes vos cases : défaite |
recharger-bonus |
rend les bonus de jeu déjà utilisés |
adversaire-maintenant |
le joueur fictif joue sans attendre son délai (même en pause) |
pause-adversaire |
met en pause / relance le joueur fictif ({ enPause } pour forcer l'état) |
reprendre-tour |
vous redonne la main |
invincibilite |
{ joueur: 'moi' | 'adversaire', actif } : les bateaux de ce joueur ne peuvent plus être touchés |
definir-bonus |
{ joueur, bonus, nombre } : exemplaires restants d'un bonus (0 à 99) |
forcer-tir-adverse |
l'adversaire tire sur { colonne, ligne } de votre grille — dans le panneau, « Viser ma grille » puis clic |
Côté client, le panneau affiche aussi la case survolée (coordonnées), un journal (états reçus, actions, erreurs, connexion WebSocket), permet de copier l'état en JSON, et règle la vitesse des animations (×0,25 à ×10, ou instantané). Le panneau a une section Triche : invincibilité de chaque joueur (case à cocher) et tableau des bonus restants des deux joueurs (−, +, ou saisie). Contre un joueur invincible, un tir sur ses bateaux compte comme raté (et un pigeon touché ne s'envole pas) ; les règles ignorent les tirs ratés pour savoir si un bateau est coulé.
Le serveur n'accepte ces actions qu'en développement (php -S, ou NAVALE_DEV=1 — que pnpm serveur définit
pour l'API comme pour le serveur WebSocket), ou, en production, d'un développeur administrateur connecté.
Deux actions s'ajoutent : difficulte ({ difficulte }, « expert » compris) et interrompre (fin sans vainqueur).
Espace développeur
Adresse /#dev (lien discret en bas de page). L'inscription est fermée : les comptes se gèrent sur le serveur.
php server/creer-developpeur.php leo # crée le compte (admin) ou change son mot de passe
php server/creer-developpeur.php alice --role observateur # rôle : admin (tout) ou observateur (lecture seule)
php server/creer-developpeur.php --lister
php server/creer-developpeur.php --supprimer alice
# Avec Docker :
docker compose exec app php /var/www/server/creer-developpeur.php leo
| Onglet | Contenu (✱ : administrateurs seulement) |
|---|---|
| Parties | liste, observation en temps réel, relecture coup par coup, carte de probabilités du tireur adverse, export JSON ; ✱ purge, suppression, interventions rangées par thème (déroulement, joueur fictif, tirs et événements dont le tir forcé par clic sur une grille, et par joueur : invincibilité, stock de chaque bonus, recharge, tout exploser, victoire immédiate), prise de la place du joueur fictif, parties de test aux flottes imposées |
| Joueurs | comptes joueurs (inscription, dernière activité, sessions, parties en ligne), catalogue des badges et historique des bannissements ; ✱ renommer, nouveau mot de passe, fermer les sessions, supprimer (les parties restent, sous le dernier pseudo), bannir du jeu en ligne, lever un bannissement, créer des badges et les attribuer ou retirer un par un |
| Statistiques | parties par jour, résultats contre le joueur fictif par difficulté, durée moyenne, bonus et événements utilisés |
| Simulation | ✱ parties entre deux niveaux du joueur fictif (règles simplifiées : tirs simples) |
| Serveur | santé (signe de vie du WebSocket, base, erreurs récentes) ; ✱ interrupteurs (événements, parties à deux, chaque bonus) et purge automatique |
| Base | diagnostic MariaDB : intégrité (CHECK TABLE), clés étrangères, schéma, cohérence, verrous récents, connexions, espace libre, volumes ; ✱ analyse, optimisation (OPTIMIZE TABLE), nettoyage |
| Audit | qui a fait quelle action d'administration, et quand |
| Compte | sessions ouvertes (révocables), changement de mot de passe |
Un administrateur connecté a aussi le panneau DEV en jeu. Les statistiques portent sur les parties conservées (la purge les retire), sauf bonus et événements, journalisés à part.
Easter eggs
Attention, ça gâche la surprise
| Déclencheur | Effet |
|---|---|
| Code Konami (↑ ↑ ↓ ↓ ← → ← → B A) | les bateaux dansent, les pigeons tourbillonnent |
| Taper « pigeon » | « Rou-rou ! », les pigeons font la toupie |
| Cliquer 7 fois sur le titre (en moins de 2 s) | « Bataille de pigeons » (et retour) |
| Viser les quatre coins de la grille adverse | une remarque sur la tactique |
| Gagner sans aucun tir dans l'eau | « Amiral légendaire » |
| Taper « baguette » pendant une partie | +2 lancers de pain (une fois par partie) |
| Taper « boum » | feu d'artifice sur les deux grilles |
| Taper « plouf » | pluie de gerbes d'eau |
| Viser 5 cases consécutives en diagonale | une remarque d'échecs |
| Au moins 2 pigeons kamikazes dans la même chaîne | « Réaction en chaîne » |
| Valider une flotte alignée à gauche, bateaux empilés | « Formation de parade » |
| Lancer le jeu entre minuit et 5 h | les pigeons dorment |
| Lancer le jeu un 1er avril | poisson d'avril |
Détections dans src/game/easterEggs.ts, animations celebrer et feuxDArtifice dans boardScene.ts.
Partie à deux joueurs
Après le placement, on choisit Contre le joueur fictif, Créer une partie à deux, ou Rejoindre avec un code.
Le créateur reçoit un code (l'identifiant de la partie, 16 caractères) et un lien ?partie=<code> à transmettre ;
la partie reste à l'état attente jusqu'à ce que le second joueur la rejoigne avec sa flotte. Le créateur tire en premier.
Chacun ne reçoit que sa vue de la partie (jeton différent) ; le WebSocket prévient le créateur dès l'arrivée de l'adversaire.
Comptes joueurs : jouer en ligne (créer une partie à deux ou en rejoindre une) demande un compte. L'inscription est
ouverte (pseudo de 3 à 20 caractères, unique sans tenir compte de la casse ; mot de passe d'au moins 8 caractères), depuis
l'écran « Contre qui jouer ? ». Un développeur connecté (espace #dev, tout rôle) joue en ligne sans compte joueur,
sous le nom <identifiant> (dev). La partie contre le joueur fictif reste sans compte. Chaque joueur voit le pseudo de
son adversaire ; on ne peut pas rejoindre sa propre partie. Routes : /api/comptes/... (en tête de server/public/index.php).
Cartes : sur l'écran « Contre qui jouer ? », on choisit le thème du plateau (mémorisé dans le navigateur) —
🏝 plage tropicale, 🧊 banquise (neige, igloo, pingouins, blocs de glace, neige qui tombe), ⚓ port de nuit (quais, phare
au faisceau qui balaie le large, réverbères, caisses et tonneaux) 🌋 île volcanique (volcan fumant, lave, fumerolles,
braises), ☁️ royaume des nuages (mer de nuages, îles flottantes, moulin, montgolfière, oiseaux) ou 🌊 abysses (coraux
et algues lumineux, méduses, épave, coffre au trésor, poisson-lanterne, bulles). La carte est enregistrée avec la partie : en ligne, celui qui rejoint joue sur la carte du créateur. Purement
visuelle : les règles ne changent pas. La flotte s'adapte : navires enneigés sur la banquise, dirigeables dans les
nuages, sous-marins dans les abysses (src/engine/flottes.ts) ; et les événements aussi (voir plus haut). Thèmes décrits dans src/game/cartes.ts, décors dans src/engine/decors.ts.
Badges : distinctions honorifiques (libellé, couleur, emoji, description au survol) créées par les administrateurs et attribuées une par une aux comptes joueurs, depuis l'onglet Joueurs. Ils s'affichent à côté du pseudo (en-tête, écran de choix, grille adverse, observation) et ne donnent aucun droit.
Mode confidentiel : si l'adversaire peut voir l'écran, le bouton « 🔒 Mode confidentiel » (au-dessus de « Ma flotte »)
masque ses bateaux ; seuls restent les tirs reçus et les bateaux déjà coulés, que l'adversaire connaît. « 👁 Maintenir pour
voir » affiche la flotte tant qu'on le garde enfoncé (souris, doigt, Espace ou Entrée). Le choix est mémorisé dans le
navigateur. Un site ne peut pas savoir si deux joueurs sont dans la même pièce : quand l'adversaire joue depuis la
même adresse IP (même box, même école), le jeu propose d'activer le mode (champ memeReseau de la vue ; l'IP des
joueurs n'est jamais envoyée aux clients).
Bannissements (onglet Joueurs de l'espace développeur) : un administrateur bannit un compte du jeu en ligne avec
un motif (montré au joueur) et une durée facultative (1 h, 24 h, 7 j, 30 j ou définitif). Le navigateur ne donne pas
accès à la carte réseau (adresse MAC) : pour freiner la création d'un nouveau compte, on bannit avec lui ses
identifiants d'appareil (aléatoires, gardés dans le localStorage et envoyés dans l'en-tête X-Appareil) et, au
choix, ses adresses IP (attention : une IP peut être partagée par tout un réseau). Toute IP ou tout appareil utilisé
ensuite par le compte banni rejoint le bannissement. Inscription et jeu en ligne sont refusés depuis ces cibles ; la
partie contre le joueur fictif reste possible, et les développeurs ne sont pas concernés. Un VPN, un autre réseau ou
l'effacement des données du site contournent ces protections : elles freinent, sans être infaillibles.
Pour tester seul : deux navigateurs (ou une fenêtre privée), connectés à deux comptes différents — la session joueur est
gardée dans localStorage, partagée entre les onglets d'un même navigateur.
Déconnexion : chaque consultation de l'état (WebSocket toutes les 100 ms, ou interrogation de secours) note la
présence du joueur (joueurs.vu_le). Sans signe de vie depuis 5 s, un joueur est considéré déconnecté et son
adversaire voit un compte à rebours ; au bout de 30 s, la partie est interrompue, sans vainqueur
(parties.interrompue_par). Délais : Parties::DELAI_PRESENCE et Parties::DELAI_INTERRUPTION.
Sons
Tous les sons sont synthétisés dans le navigateur (Web Audio API, src/engine/sons.ts) : aucun fichier audio.
Tir, explosion, coulé, plouf, sonar, pigeon (« rou-rou » et battements d'ailes), trou noir et couic de canard.
Chaque événement est annoncé par une alarme de bord à deux tons, puis a son ambiance, calée sur son animation :
pluie et vent (tempête, avec le tonnerre à chaque éclair), grondement et craquements de roche (séisme), vague qui
monte puis s'écrase (raz-de-marée), rugissement puis claquement des tentacules (kraken), chant et souffle de
l'évent (baleine), glace qui gémit puis choc (iceberg), coque qui gémit et bulles (naufrage), et boum grave suivi
d'un long grondement (explosion générale du mode dev). Le bouton 🔊 de l'en-tête coupe le son (mémorisé dans le navigateur).
Les navigateurs n'autorisent le son qu'après un premier clic ou une première touche.
API
| Requête | Corps | Réponse |
|---|---|---|
GET /api/config |
— | { deuxJoueurs, bonusDesactives } (fonctionnalités désactivées par les développeurs) |
POST /api/parties |
{ bateaux, adversaire: 'fictif' | 'humain', difficulte } |
{ partieId, jeton } |
POST /api/parties/{id}/rejoindre |
{ bateaux } |
{ partieId, jeton } — le second joueur humain |
GET /api/parties/{id} |
en-tête X-Jeton |
sa flotte, ses tirs, les tirs reçus, les bateaux adverses coulés |
POST /api/parties/{id}/tirs |
{ colonne, ligne } + X-Jeton |
{ resultat: 'rate' | 'touche' | 'coule' } |
POST /api/parties/{id}/bonus |
{ bonus, colonne, ligne } + X-Jeton |
{ bonus, tirs, detectees } |
POST /api/parties/{id}/dev/{action} |
X-Jeton |
selon l'action — mode dev, voir ci-dessous |
La seule exception est le mode dev, réservé en production aux développeurs administrateurs.
Les routes /api/dev/... de l'espace développeur sont décrites en tête de server/public/index.php.
Le serveur ne renvoie jamais la flotte adverse : seuls les bateaux entièrement coulés sont révélés.
Temps réel (WebSocket)
Le client ouvre ws://<hôte>/ws (proxifié par Vite vers server/websocket.php, port 8001) et s'abonne :
{ "type": "abonner", "partieId", "jeton" }. Le serveur répond { "type": "etat", "etat" } tout de suite,
puis à chaque nouvelle version de la partie. Les tirs passent toujours par l'API HTTP : le serveur
WebSocket surveille la base toutes les 100 ms (et se reconnecte si MariaDB coupe la connexion). Il est écrit sans dépendance (poignée de main
et trames RFC 6455 à la main).
C'est aussi lui qui fait jouer le joueur fictif, JoueurFictif::DELAI secondes après le dernier coup.
Si le WebSocket est coupé, le client interroge l'API toutes les 1,5 s et se reconnecte tout seul
(le joueur fictif joue alors lors de ces consultations).
Sens des échanges :
props (état du jeu) ──▶ composant Vue ──▶ méthodes de BoardScene ──▶ rendu 3D
▲ │
└─── événements ◀────┘ (clic, survol)
Règle d'or : le composant Vue ne touche jamais un objet 3D, et le moteur ne connaît pas Vue.
Repère 3D
Lite utilise un repère main gauche : +x vers la droite, +y vers le haut, +z s'éloigne de la caméra.
La caméra est côté -z, donc la ligne 0 de la grille est en haut de l'écran.
La caméra est fixe (pas de attachControl).
Particularités de BabylonLite à connaître
- Tout ajouter avant
registerScene(): ce qui est ajouté après n'apparaît pas. C'est pourquoi les marqueurs (bateau, touché, raté) sont créés une fois pour toutes puis montrés/cachés avecsetSubtreeVisible. - Pas d'
ActionManagerni d'observable de pointeur : on écoute les événements DOM du canvas. Les coordonnées doivent être relatives au canvas (clientX - rect.left). - Les objets (caméra, mesh, matériau) sont des données ; le comportement est dans des fonctions
(
addToScene(scene, mesh),setSubtreeVisible(mesh, false)…).
Reste à faire
Rien pour l'instant. (En production, l'image Docker fait passer /ws par Apache vers le serveur WebSocket.)
Crédits
Modèles de bateaux : Watercraft Kit de Kenney (www.kenney.nl),
licence CC0 — copie de la licence dans public/modeles/LICENCE-Kenney.txt.