📊 Vue d'Ensemble du Code

ArcLycée est un RPG 2D écrit en JavaScript vanilla (ES Modules) sans frameworks ni bundlers. Tout le rendu est réalisé avec HTML5 Canvas, les effets sonores sont générés par code avec Web Audio API, la musique de fond utilise des fichiers MP3 avec fondu enchaîné, et tous les sprites sont dessinés de manière procédurale.

MétriqueValeur
Fichiers JavaScript53
Total de lignes de code~37 500
Résolution du canvas960 × 540 px (16:9)
FPS cible60
Langues supportées3 (Español, Français, English)
Clés de traduction~1 100+
Effets sonores procéduraux60 méthodes
Mondes jouables12 + carte du monde
Mini-jeux4 (batú, calibration, programmation, câbles)

Arborescence des Répertoires

RépertoireContenuFichiers
js/motor/Boucle de jeu, entrée, rendu, son, sauvegarde, configuration6
js/escenas/Menu principal, sélection du personnage, intro, cinématique finale4
js/mundos/13 niveaux jouables : grottes, villages, montagne, colonial, aquatique, juridique, laboratoire, LFSD, lac, cenote, musée13
js/mecanicas/Combat, dialogue, inventaire, album photo, 4 mini-jeux, quêtes, réputation, journal11
js/personajes/Joueur (Pepito/Pepita) + 3 compagnons (Magnoboot, Viralata, Cemí)4
js/idiomas/Traductions ES/FR/EN + gestionnaire de langues4
js/mapas/Carte Leaflet avec couches de données réelles (taïno, colonial, naufrages, musées)4
js/clima/Système météo + ouragans2

Technologies

TechnologieUtilisation
HTML5 CanvasRendu du jeu — tout est dessiné par code, aucun sprite externe
JavaScript ES ModulesArchitecture modulaire sans frameworks ni bundlers
Web Audio API60 effets sonores procéduraux + musique de fond avec 24 MP3
LeafletJS + Stadia MapsCartes interactives avec 76 sites archéologiques réels de RD et Haïti
Kaplay.jsEntrée tactile (joystick analogique et D-pad)
CSS3Écran de chargement, contrôles tactiles responsive

Principes de Conception

🔄 Boucle de Jeu et Gestion des Scènes

Fichier : js/motor/juego.js (1 659 lignes) — l'orchestrateur principal du jeu.

Boucle Principale

Le jeu tourne à ~60 FPS grâce à requestAnimationFrame. Chaque image calcule le delta time et exécute deux phases : mise à jour (logique) et dessin (rendu).

Le delta time est plafonné à 0,1 seconde pour éviter la « téléportation » du joueur lorsqu'il revient d'un autre onglet :

dt = Math.min((currentTime - previousTime) / 1000, 0.1)

Système de Scènes

Le jeu possède 15 scènes enregistrées. Une seule scène est active à la fois.

TypeScènes
InterfaceMenu principal, sélection du personnage, cinématique d'intro, cinématique finale
Mondes jouables (9)Grottes de Pomier, Asentamiento I, Asentamiento II, La Isabela, Zone Coloniale, Monde Aquatique, Aéroport, Laboratoire, LFSD
NavigationCarte du monde (carte en tuiles)
SecretSélecteur de niveaux (Code Konami)

Cycle de Vie des Scènes

Chaque scène implémente trois méthodes :

Les changements de scène utilisent juego.cambiarEscena('nom'), qui appelle salir() sur la scène précédente, crée le joueur si la nouvelle scène est jouable, et appelle iniciar(juego) sur la nouvelle. Le retour à la carte du monde déclenche la sauvegarde automatique.

Système de Couches Superposées

Les couches superposées sont dessinées par-dessus la scène active, dans cet ordre (de bas en haut) :

  1. Scène de base
  2. Effets météo (pluie, orages)
  3. Combat — rencontre ennemie
  4. Batú — jeu de balle taïno
  5. Mini-jeux LFSD — calibration, programmation, câbles
  6. Journal de jeu — suivi des quêtes (touche L)
  7. Jauge de réputation — barre HUD
  8. Album photo — galerie (touche P)
  9. Indice photo/selfie (touches T/G)
  10. Inventaire — sac à dos (touche I)
  11. Notifications — messages flottants (max 4 empilés)
  12. Sélecteur secret — toujours au premier plan

Système de Notifications

juego.mostrarToast(texte, durée) ajoute un message flottant. Ils s'empilent verticalement (max 4), avec un fondu de 0,3 s à l'apparition et dans la dernière seconde. Utilisé pour la collecte d'objets, l'achèvement des quêtes, les alertes de danger, etc.

Système de Mort

Quand le joueur atteint 0 point de vie : son comique « wah wah waaah », message de mort aléatoire (4 s), pause de 2,5 s, puis réapparition sur la carte du monde avec 30 % de vie restaurée. Un drapeau _muerteEnCurso empêche de déclencher la mort plusieurs fois.

🎮 Système d'Entrée

Fichier : js/motor/entrada.js (494 lignes) — couche d'abstraction unifiée pour clavier et tactile.

Contrôles Clavier

ActionTouchesUtilisation
Se déplacerZQSD / FlèchesExploration et menus
SauterEspaceGrottes uniquement (plateforme)
InteragirE / EntréeParler aux PNJ, utiliser des objets
InventaireIOuvrir/fermer le sac à dos
SpécialFDétecteur de métaux (Magnoboot)
Retour à la carteMQuitter le niveau en cours
Carte réelleROuvrir la carte Leaflet de référence
JournalLJournal de jeu (quêtes)
PhotoTPhotographier une entité proche
SelfieGSelfie avec une entité
AlbumPConsulter la galerie photo
Zoom+ / -Zoom sur la carte du monde
Code Konami↑↑↓↓←→←→Sélecteur de niveaux secret

API Unifiée

Toutes les requêtes d'entrée passent par entrada.estaPresionada(action), qui combine clavier et tactile. En interne, deux objets Map sont utilisés : teclasPresionadas pour le clavier et accionesTocadas pour le tactile.

Contrôles Tactiles

Deux modes commutables depuis le menu Options (préférence sauvegardée dans localStorage) :

5 boutons d'action à droite : A (action), B (annuler), X (inventaire), Y (spécial), SAUT. Utilise touchstart/touchend au lieu de click pour éviter le délai de 300 ms sur mobile.

Patron de Blocage d'Entrée

Pour empêcher une touche de se « répéter » quand elle est maintenue, un drapeau bloqueoEntrada est utilisé : activé lors du traitement de l'action et désactivé uniquement au relâchement de la touche. Initialisé à true en entrant dans les scènes où la touche d'activation pourrait être enfoncée.

Prévention des Touches « Collées »

L'événement window.blur efface toutes les touches enfoncées. Cela empêche le joueur de continuer à se déplacer en revenant d'un autre onglet avec une touche de mouvement maintenue.

🖼️ Rendu et Effets Visuels

Fichier : js/motor/renderizado.js (199 lignes) — wrapper Canvas 2D.

Configuration du Canvas

Résolution fixe de 960×540 (moitié de 1080p, facile à agrandir). Le lissage d'image est désactivé (imageSmoothingEnabled = false) pour conserver la netteté du pixel art.

Opérations Principales

MéthodeDescription
limpiar()Efface l'image précédente avec clearRect
dibujarRectangulo()Rectangle plein (collisions, placeholders)
dibujarTexto()Texte avec police, couleur et alignement configurables
dibujarBarra()Barre de progression avec pourcentage limité à [0, 1] et bordure noire

Effet de Torche dans les Grottes

aplicarFiltroCueva(playerX, playerY, lightRadius) crée un effet de torche grâce à un dégradé radial avec un centre transparent et des bords opaques :

Effet de Secousse

Les mondes aquatiques utilisent un minuteur _sacudida qui, lorsqu'il est activé (par collision avec une vedette, morsure de requin ou méduse), applique une oscillation horizontale au sprite du joueur :

ctx.translate(Math.sin(totalTime * 50) * amplitude * intensity, 0)
// intensity = _sacudida / initialDuration (décroît linéairement)

Tri par Profondeur

Dans les mondes aquatiques, les entités (PNJ, tortues, méduses, joueur) sont triées par leur coordonnée Y avant le dessin, créant un effet de profondeur naturel où les objets proches recouvrent les plus éloignés.

🔊 Système Audio Procédural

Fichier : js/motor/sonido-procedural.js (1 931 lignes) — 60 effets sonores générés par code.

Les effets sonores sont synthétisés en temps réel en combinant des oscillateurs (sinusoïdal, carré, dent de scie, triangle), des filtres (passe-bas, passe-haut, passe-bande), des tampons de bruit blanc et des enveloppes de gain. La musique de fond est lue depuis des fichiers MP3 avec fondu enchaîné automatique.

Motifs Fondamentaux

Initialisation Paresseuse

Les navigateurs bloquent Web Audio jusqu'à la première interaction utilisateur. _asegurarContexto() crée l'AudioContext uniquement à la première utilisation.

Balayage de Fréquence

La plupart des sons utilisent un balayage de fréquence (rampe exponentielle ou linéaire) pour créer une sensation de mouvement :

osc.frequency.setValueAtTime(startFreq, now)
osc.frequency.exponentialRampToValueAtTime(endFreq, now + duration)

Enveloppe d'Amplitude (ADSR Simplifié)

Contrôle le volume dans le temps : attaque rapide → maintien → décroissance exponentielle vers le silence.

Bruit Blanc

Généré en remplissant un tampon avec des valeurs aléatoires (-1 à 1), puis filtré pour créer différentes textures : pas (passe-bas 800 Hz), étincelles (passe-haut 2000 Hz), foule (passe-bande 600 Hz).

LFO (Oscillateur Basse Fréquence)

Un oscillateur basse fréquence (4-30 Hz) module un autre paramètre (généralement la fréquence principale) pour créer du vibrato, du wobble ou des sirènes :

lfo.frequency.value = 4     // wobble à 4 Hz
lfoGain.gain.value = 8      // profondeur de modulation ±8 Hz
lfo → lfoGain → osc.frequency

Catalogue de Sons (60 méthodes)

Locomotion et Retour d'Information (7)

MéthodeTechniqueDescription
salto()Carré 150→400 HzSaut du joueur
aterrizar()Sinusoïdal 100→40 HzAtterrissage
recoger()Deux notes carrées (523, 659 Hz)Collecte d'objet
paso()Bruit blanc 40 ms, passe-bas 800 HzPas
goteo()Sinusoïdal 800→240 Hz, aléatoireGoutte d'eau
dano()Dent de scie 200→50 HzDégât générique
muerte()Trois notes descendantes en dent de scie avec LFOComique « wah wah waaah »

Combat (17)

MéthodeDescription
combateAtacar()Dent de scie agressive 400→100 Hz
combateHablar()Deux sinusoïdales simultanées (300, 350 Hz), paisible
combateNegociar()Deux notes carrées alternées avec pause
combateRedesSociales()Deux « ding-ding » sinusoïdaux (notification téléphone)
combateProtestas()Trois impulsions carrées (rythme de slogan de manifestation)
combateDenuncia()Bruit + sinusoïdal 150→60 Hz (tampon officiel)
combateViaLegal()Triangle 180→90 Hz (marteau de juge)
combateAtrapar()Bruit passe-bande 1200 Hz (filet de pêche)
combatePescar()Sinusoïdal 200→800 Hz + bruit passe-bas (harpon + éclaboussure)
combateProtegerCoral()Accord majeur chaleureux à trois notes
combateAlertarBuzos()Carré 700 Hz avec LFO 8 Hz (sifflet sous-marin)
combateLey318()Triangle 200→100 Hz (coup de marteau judiciaire)
combateEvidenciaForense()Deux bips sinusoïdaux (caméra/scanner)
combateInterpol()Carré 600→800→600 Hz (bip de sirène de police)
combateUnesco()Accord majeur solennel (autorité diplomatique)
combateVictoria()Arpège ascendant triomphal
combatePacificado()Accord majeur soutenu 0,5 s (paix atteinte)

Batú (5)

MéthodeDescription
batuGolpe()Triangle 120→60 Hz (impact balle sur pierre)
batuRebote()Sinusoïdal 300→150 Hz (rebond caoutchouc)
batuPunto()Arpège ascendant à trois notes (point marqué)
batuSaque()Sinusoïdal 600→800 Hz (coup de sifflet de service)
batuMultitud()Bruit blanc passe-bande 600 Hz (rugissement de foule)

Ambiance Aquatique (4)

MéthodeDescription
cantoBallenaCerca()Trois longues notes sinusoïdales avec LFO individuel, passe-bas 600 Hz (vocalisation de baleine à bosse)
manatiLlamada()Sinusoïdal 80→120→90→110 Hz oscillant (appel ondulant du lamantin)
lanchaImpacto()3 couches : impact triangle 200→40 Hz + éclaboussure de bruit + cri de Wilhelm synthétique (dent de scie avec LFO 30 Hz)
mordidaTiburon()3 couches : craquement de mâchoire (bruit passe-haut 3000 Hz) + impact profond + grognement avec LFO 12 Hz

Mini-jeux LFSD (15)

MéthodeDescription
calibracionTono(freq)Sinusoïdal à la fréquence donnée, 0,2 s
calibracionExito()Arpège majeur ascendant (4 notes)
calibracionFallo()Deux impulsions descendantes en dent de scie
calibracionAjuste()Bruit passe-haut 2000 Hz, 20 ms (clic de molette)
bloqueColocar()Carré 800→400 Hz + bruit (bloc enclenché)
bloqueQuitar()Sinusoïdal ascendant 300→600 Hz (bloc retiré)
robotMoverse()Dent de scie modulée 120→180→120 Hz (servomoteur)
robotExito()Arpège triomphal en carré à 4 notes
robotFallo()Deux bips carrés descendants
cableConectar()Sinusoïdal 1200→600 Hz + bruit de contact
cableError()Dent de scie + bruit passe-haut 3000 Hz (étincelle électrique)
circuitoCompleto()Sinusoïdal exponentiel + triangle (mise sous tension du circuit)
robotFLLIniciar()Dent de scie continue avec ronronnement de moteur (démarrage du robot FLL à chenilles)
robotFLLDetener()Arrête le moteur avec fondu sortant progressif (arrêt du robot FLL)
robotFLLClick()Clic mécanique court (inutilisé actuellement)

Ambiance et Interface (4)

MéthodeDescription
dialogo()« Bleep » carré rapide 380±40 Hz (caractère de texte style Undertale)
fotoCaptura()Bruit 0,08 s + carré 1200→300 Hz (obturateur + clic mécanique)
selfieCaptura()Bruit 0,06 s + sinusoïdal ascendant 400→1200 Hz (obturateur + flash)
lluviaAmbiente()Boucle continue : bruit filtré + gouttes périodiques toutes les 150-350 ms

Musique de Fond (js/motor/musica.js)

La classe SistemaMusica gère la musique de fond du jeu à l'aide de fichiers MP3. Contrairement aux effets sonores (procéduraux), la musique utilise 24 fichiers audio réels organisés en 12 groupes thématiques (2 pistes par groupe).

Groupes Musicaux (12 groupes, 24 MP3)

GroupeScène(s)Description
menumenuPrincipalMusique du menu principal
cuevascuevasPomierAmbiance de grottes
tainoMondes taïnos (villages)Musique indigène
colonialMondes coloniauxÉpoque coloniale
acuaticoMonde AquatiqueAmbiance sous-marine
aeropuertoMonde JuridiqueAéroport de Punta Cana
museoMonde LaboratoireIntérieur de musée
lfsdLFSDSalle de robotique
mapamapaPrincipalCarte du monde
creditosfinalCinematicaCinématique finale et crédits

Fondu Enchaîné A-B

Chaque groupe possède 2 pistes (A et B). Lorsqu'une piste se termine, le système effectue un fondu enchaîné de 2 secondes vers l'autre piste, créant une boucle continue sans silence (A → B → A → B...). Les deux pistes utilisent HTMLAudioElement et le volume est interpolé linéairement pendant la transition.

Interruption Combat et Batú

Lorsqu'un combat ou une partie de batú commence, la musique de fond est temporairement mise en pause. À la fin de l'overlay, la musique du scénario est automatiquement restaurée.

Contrôle du Volume

Le volume de la musique (0-100 %) se configure depuis le menu Options. La préférence est sauvegardée dans localStorage sous la clé arclycee_volumen_musica et restaurée au démarrage du jeu.

Autoplay du Navigateur

Les navigateurs bloquent la lecture automatique de l'audio jusqu'à la première interaction utilisateur. Si la tentative de lecture initiale échoue, le système réessaie automatiquement lorsque la première pression de touche est détectée dans le menu principal.

⚔️ Système de Combat

Fichier : js/mecanicas/combate.js (932 lignes) — combat au tour par tour style Undertale avec voie pacifiste.

Concept

Le combat dans ArcLycée n'est pas un échange de dégâts traditionnel. L'objectif est de convaincre l'ennemi par des actions diplomatiques. Deux jauges émotionnelles :

Déroulement des Tours

  1. Tour du joueur : choisir parmi les options (←→ pour naviguer, E pour confirmer)
  2. Retour : message doré avec le résultat de l'action (1,8-2,5 s)
  3. Tour de l'ennemi : l'ennemi répond en fonction de la dernière action du joueur
  4. Répétition jusqu'à patience = 100 (victoire pacifiste) ou PV de l'ennemi = 0 (victoire par la force)

Options Personnalisées par Ennemi

Chaque ennemi peut avoir des opcionesPersonalizadas — un tableau d'actions uniques avec des plages aléatoires de patience/hostilité et des contre-réponses spécifiques :

EnnemiOptionsÉtiquette
Constructor MéndezRéseaux sociaux, Manifestations, Dénonciation, Voie légale« Convaincu : »
Poisson-lionCapturer, Pêcher, Protéger le corail, Alerter les plongeurs« Contrôlé : »
Rodrigo TorresLoi 318, Preuves médico-légales, INTERPOL, UNESCO 1970« Preuves : »

Sprites d'Ennemis

4 types de sprites dessinés de manière procédurale : _dibujarSoldado(), _dibujarConstructor(), _dibujarPezLeon(), _dibujarTraficante(). Chacun avec un design et une animation uniques.

Sous-menu de Compagnons en Attaque

Lorsque le joueur choisit d'attaquer et a des compagnons actifs, un sous-menu apparaît demandant « Avec qui attaquez-vous ? » avec les options : Solo / Magnoboot +3 / Viralata +2 / Cemí +4. Navigation avec les flèches (haut/bas), E pour confirmer, Q pour annuler et revenir au menu principal de combat.

Panneau d'Aide (touche H)

Un overlay basculable avec la touche H qui explique les objectifs du combat, les différences entre la voie pacifiste et la voie agressive, la signification des jauges (patience, hostilité, vie) et les récompenses de réputation selon le type de victoire.

Indicateur d'État

Texte dynamique indiquant qui a l'avantage dans le combat. Change selon les valeurs de patience et d'hostilité : « Presque convaincu », « Très hostile », « En progression », « Situation tendue ».

[E] Continuer

Les messages d'action du joueur et les contre-attaques de l'ennemi s'affichent pendant 2,5 secondes. Ensuite, un bouton pulsant [E] Continuer apparaît, que le joueur doit presser pour passer au tour suivant.

Barre de Vie Cachée

Pour les ennemis ayant des opcionesPersonalizadas, la barre de vie de l'ennemi est masquée. Ces ennemis se battent par conviction (patience = 100), pas par dégâts de vie.

Intégration de la Réputation

Victoire pacifiste = +15 réputation. Victoire par la force = +5. De plus, la réputation actuelle du joueur confère un avantage initial : initialPatience = min(reputation / 2, 25).

💬 Système de Dialogue

Fichier : js/mecanicas/dialogo.js (326 lignes) — moteur de dialogue avec effet machine à écrire.

Effet Machine à Écrire

Les caractères apparaissent un par un. Un compteur _caracteresVisibles s'incrémente à chaque image, et le texte affiché est text.substring(0, Math.floor(characters)). Chaque caractère déclenche un « bleep » de dialogue (son procédural).

Options de Réponse

Les lignes de dialogue peuvent inclure opciones: [{texto, valor}]. Quand des options sont présentes, l'avancement est bloqué jusqu'à ce que le joueur en sélectionne une (↑↓ pour naviguer, E pour confirmer).

Callback d'Enchaînement

alTerminar permet d'enchaîner des événements après la fin d'un dialogue : lancer un combat, donner un objet, découvrir une quête, etc.

Dialogue Rotatif

Les PNJ mentors (Roberto Cassá, Lcda. Carmen Vidal) utilisent un compteur qui s'incrémente après chaque conversation. L'indice est calculé comme counter % array.length pour boucler indéfiniment sur les sujets.

🤝 Système de Compagnons

Répertoire : js/personajes/companeros/ — trois compagnons qui suivent le joueur à travers les scènes.

Patron Commun

Tous partagent : une propriété tipo (chaîne), un drapeau activo, des méthodes activar()/desactivar(), et un mouvement par interpolation linéaire (lerp) pour un suivi fluide au lieu d'une téléportation.

Les Trois Compagnons

NomTypeCapacitéFacteur LerpPosition Relative
MagnobootRobot excavateurDétecteur de métaux (touche F), excavation (coûte 10 énergie)0,05À droite du joueur (+30, +5)
ViralataChien pisteurFlair (rayon 50 px), remue la queue quand des objets sont détectés0,06À gauche du joueur (-25, +10)
Cemí MurciélagoEsprit des grottes6 niveaux de pouvoir débloqués avec des botijas (écho-location → vision cemí)0,08En haut à gauche (-20, -25) avec flottement sinusoïdal

Persistance

Les compagnons persistent entre les scènes via juego.companeros[]. Dans les sauvegardes, ils sont sérialisés comme {tipo, activo} et reconstruits avec _crearCompaneroBasico(tipo, activo).

🎒 Système d'Inventaire

Fichier : js/mecanicas/inventario.js (742 lignes) — sac à dos visuel avec grille de 20 emplacements.

Conception

Grille de 5 colonnes × 4 lignes. Chaque emplacement mesure 52×52 px avec 4 px de marge. Le panneau est centré sur le canvas. Navigation avec les flèches, utilisation de l'objet avec E (si esUsable).

Objets de Soin

ObjetSoinSource
Guanábana+30 PVGuarionex (Asentamiento II)
Vasija curativa+35 PVAnacaona (Asentamiento I)
Casabe+25 PVDivers

Icônes Procédurales

Plus de 24 icônes uniques dessinées avec Canvas 2D : torche avec rayons lumineux, cemí doré avec yeux, boussole avec aiguilles rouge/blanche, arquebuse coloniale, pièce avec couronne, etc. _dibujarIconoObjeto(ctx, id, x, y, size) dispatche vers l'icône correcte selon l'ID.

📸 Album Photo

Fichier : js/mecanicas/album-fotos.js (1 140 lignes) — système de capture avec rendu dédié par type d'entité.

Types de Capture

Rendu par Type d'Entité

Le champ tipoEntidad détermine quel moteur de rendu utiliser. Les scènes exposent un tableau fotografiables[] pour les entités supplémentaires au-delà des PNJ :

tipoEntidadMoteur de renduDétail
'npc'_renderizarNPCCentrado()Dessine le PNJ sur un canvas auxiliaire 200×200, détecte la boîte englobante par pixels, recadre et centre
'tortuga'_renderizarTortuga()4 sprites dédiés : imbriquée (olive avec rayures ambrées), luth (bleu-noir avec 7 crêtes), caouanne (brun-rouge avec marque en cœur), verte (olive avec taches)
'coral'_renderizarCoral()4 sprites : cerveau (hémisphère avec sillons sinueux), corne de cerf (5 branches bifurquées), éventail (violet-rose avec nervures radiales), table (plateforme elliptique sur tronc)
'petroglifo'_renderizarPetroglifo()4 types : soleil, chauve-souris, visage, spirale
'objeto'_renderizarObjeto()Objet de collection générique avec lueur

Portée de Détection

La détection de la cible photo utilise la distance euclidienne avec un rayon de 80 px (RANGO_FOTO). La recherche s'effectue d'abord parmi les PNJ, puis les objets, puis les fotografiables[].

🗺️ Carte en Tuiles (Hispaniola)

Fichier : js/mundos/mapa-tiles.js (784 lignes) — génération procédurale de terrain pour l'île.

Le Bitmap

Le littoral d'Hispaniola est défini avec ISLA_BITMAP : un tableau de 68 chaînes de 128 caractères chacune. Chaque caractère est '1' (terre) ou '0' (eau). Tracé manuellement à partir d'une image de référence NASA, mis à l'échelle 2× depuis un bitmap original de 64×34.

Pipeline de Génération de Terrain

  1. Initialiser toutes les tuiles comme DEEP_WATER
  2. Marquer les tuiles de terre depuis ISLA_BITMAP
  3. Ajouter l'eau peu profonde adjacente à la côte (bordure de 1 tuile)
  4. Peindre les plages (terre adjacente à l'eau)
  5. Appliquer les chaînes de montagnes par distance point-segment (8 cordillères)
  6. Ajouter les lacs intérieurs (Enriquillo, Saumâtre) par collision d'ellipse
  7. Générer les forêts avec un hash pseudo-aléatoire (40 % de probabilité par tuile)
  8. Dessiner 5 rivières avec l'algorithme de Bresenham (Yaque del Norte/Sur, Yuna, Ozama, Artibonite)

8 Types de Terrain

TypePraticableDécoration
Eau profondeNonCourbes de vagues animées
Eau peu profondeOuiÉcume
SableOuiTexture granuleuse
PrairieOui
ForêtOuiCouronnes d'arbres (cercles)
MontagneNonTriangles avec sommets rocheux
RivièreOuiLignes de courant animées
CheminOui

Algorithme de Bresenham pour les Rivières

Les rivières sont tracées en reliant des points de passage avec l'algorithme de Bresenham. Seules les tuiles déjà terrestres sont peintes (les tuiles d'eau sont ignorées), créant des rivières qui coulent naturellement le long du terrain.

Chaînes de Montagnes par Distance

8 chaînes de montagnes définies comme des séquences de points de passage. Pour chaque tuile terrestre, la distance minimale à chaque segment de chaîne est calculée. Si elle est inférieure à 3,6 tuiles, la tuile devient une montagne (non praticable).

Élimination par Vue

dibujarTilesVisibles() ne rend que les tuiles situées dans le champ de la caméra, en calculant les colonnes et lignes de début et de fin. Cela est crucial pour les performances étant donné que la carte fait 128×68 = 8 704 tuiles au total.

🧭 Carte du Monde

Fichier : js/mundos/mapa-principal.js (809 lignes) — navigation entre les nœuds de niveau.

Système de Caméra

Nœuds de Niveau

13 nœuds placés à des coordonnées de tuiles praticables vérifiées. Chacun possède : un ID, une position, un type (grotte, village, ville, naufrage, etc.), une scène de destination, et le nœud précédent dans la chaîne de progression.

Affichage : cercle (18-22 px) + bordure + icône emoji + nom. Les couleurs indiquent l'état : gris (verrouillé), or (actif), vert (complété). Un indicateur doré pulsant [E] apparaît quand le joueur est à proximité.

Mini-Carte

Coin supérieur droit (120×75 px). Affiche des tuiles simplifiées (pas de 2 pour les performances), les nœuds colorés par état, la position du joueur et le champ de la caméra.

Collision

_puedeMoverse() teste les 4 coins du sprite (avec 4 px de marge) par rapport au esCaminable() de la carte en tuiles.

🌊 Mécaniques Aquatiques

Fichiers : js/mundos/acuatico/mundo-acuatico.js (2 174 lignes) + santuario-manati.js (2 905 lignes).

Mouvement Sous-marin

ConditionFacteur de Vitesse
Normal (sous l'eau)× 0,7
Avec effet de méduse× 0,4
Avec effet de requin× 0,4 (durée 2 s)

Méduses Passives

4 méduses avec mouvement sinusoïdal entre deux points de passage : t = (sin(phase + dt*0.8) + 1) / 2 → lerp entre pointA et pointB. Contact (rayon 15-20 px) = 5 PV de dégâts + 2,5 s de lenteur + 2 s d'invulnérabilité.

Vie Marine

Système d'Oxygène (Sanctuaire du Lamantin)

Le joueur nage en apnée avec un tuba. Barre d'O₂ de 100 à 0 :

Requins

3 requins patrouillent entre des points de passage avec décalage de phase (0, π/2, π). Morsure : -8 PV + 2 s de lenteur + effet de secousse (0,5 s) + son mordidaTiburon().

Vedettes Rapides

Apparition toutes les 5-15 s dans la zone de surface. Collision : -10 PV + secousse (0,6 s) + cri de Wilhelm synthétique (lanchaImpacto()). La zone d'hélice cause des dégâts périodiques (-2 PV avec intervalle). Notification d'avertissement affichée une seule fois par entrée dans la zone.

Actions Écologiques

⛈️ Système Météo

Fichiers : js/clima/clima.js (442 lignes) + huracan.js (324 lignes).

6 États Météorologiques

ÉtatProbabilitéIntensitéEffet sur le Joueur
Ensoleillé45 %0,1Aucun
Nuageux25 %0,3Aucun
Pluie20 %0,6Vitesse × (1 − 0,15×i)
Orage7 %0,8Vitesse × (1 − 0,25×i) + tonnerre
Ouragan2 %1,0Poussée du vent 2px×i + vitesse × (1 − 0,35×i)
Tremblement de terre1 %2 % de chance de trébucher par image

Particules

Jusqu'à 500 particules recyclées. Taux d'apparition : 3-8 particules/image selon l'intensité. Chaque particule subit la gravité + la poussée du vent.

Ouragans (Avancé)

Catégories 1-5 avec vitesse du vent = catégorie × 2 px/image. Trois phases : début (0-25 %, intensité croissante) → pic (25-75 %, intensité maximale) → fin (75-100 %, intensité décroissante). Physique des débris avec jusqu'à 500 objets rebondissant sur le terrain. Direction : typiquement depuis l'est (réaliste pour les Caraïbes).

Son Ambiant

Pluie continue (lluviaAmbiente()) avec intensité dynamique pendant les transitions. Tonnerre aléatoire toutes les 4-15 s pendant les orages.

🎲 Mini-Jeux

Monde LFSD — Classe de Robotique

Fichier : js/mundos/lfsd/mundo-lfsd.js — niveau intérieur de la salle de robotique du Lycée Français de Saint-Domingue.

Le Prof. Nicolas Droulers (cheveux blancs et barbe blanche) guide le joueur. La salle contient des tables de travail avec des écrans de programmation Scratch, un tableau, une imprimante 3D avec une étiquette traduite selon la langue active, et une table FIRST LEGO League avec des chemins noirs de suivi de ligne où un robot LEGO animé à chenilles suit les pistes avec un son de moteur (robotFLLIniciar/robotFLLDetener). 9 PNJ étudiants (3 donneurs de quêtes avec des T-shirts de couleur) et 4 postes de travail.


Batú — Jeu de Balle Taïno

Fichier : js/mecanicas/batu.js (935 lignes) — physique 2D avec IA adaptative.

Physique

ParamètreValeur
Gravité480 px/s²
Coefficient de rebond (sol)0,8
Coefficient de rebond (murs)0,9
Friction de l'air0,998 par image
Rayon de la balle8 px
Condition de victoirePremier à 3 points

Types de Frappe (par hauteur de contact)

ZonePartie du corpsVitesseAngle
< 25 %Tête290 px/s-70° (quasi vertical)
25-50 %Épaule425 px/s-60°
50-75 %Hanche/yugo500 px/s (max)-45° (le plus puissant)
> 75 %Genou280 px/s-30° (défensif)

Chaque frappe a une variation de ±25 % en vitesse et ±8° en angle pour l'imprévisibilité.

Adversaire IA

Données Éducatives

Entre chaque point, un fait historique sur le batú est affiché : matériau de la balle (latex de l'arbre cupey), pétroglyphes du batey, le yugo cérémoniel, les festivals areíto, la résolution pacifique des conflits, et des sites archéologiques réels (Chacuey, La Aleta).

Phases

intro → service → jeu → point → éducation → service → ... → finPartie


Calibration du Signal (« Bonnes Vibrations »)

Fichier : js/mecanicas/calibracion-senal.js (330 lignes) — puzzle d'oscilloscope.

Mécanique

3 cadrans (fréquence, amplitude, phase) contrôlant une onde sinusoïdale affichée sur un oscilloscope (vert sur noir). Le joueur doit reproduire l'onde cible avec une tolérance de ±15 %.

Formule de l'Onde

y = centerY + sin(t + phase) × amplitude
where t = (x − 40) / (width − 80) × π × 2 × frequency

Contrôles

↑↓ pour changer de cadran, ←→ pour ajuster (±2), E pour confirmer. Limite de temps : 45 secondes.

Récompense : magnétomètre calibré (progreso.magnetometroCalibrado = true), +15 réputation.


Programmation du Robot (« Full Metal Archeologist »)

Fichier : js/mecanicas/programacion-bloques.js (491 lignes) — navigation par blocs.

Mécanique

Disposer 5-6 blocs d'instructions (avancer, tourner à gauche/droite, scanner, plonger, remonter) pour guider un robot sous-marin à travers une grille 6×4. Le robot commence à (0,1) face à droite, cible à (5,2).

Exécution

Max 12 blocs. Intervalle d'exécution : 0,6 s entre les étapes. Échec : le robot sort de la grille ou percute un obstacle (s'il n'est pas immergé). Phase de programmation : 60 s. Exécution : automatique, sans limite de temps.

Récompense : couche de sites archéologiques sur la carte Leaflet (progreso.robotProgramado = true), +15 réputation.


Connexion de Câbles (« Weird Science »)

Fichier : js/mecanicas/conexion-cables.js (408 lignes) — puzzle d'appariement sur un circuit imprimé.

Mécanique

Connecter 6 entrées (gauche) à 6 sorties (droite) par couleur et symbole. Sorties en ordre aléatoire. Les connexions sont dessinées sous forme de courbes de Bézier cubiques. Mauvaise connexion = animation d'étincelle.

Contrôles

↑↓ pour sélectionner l'entrée/sortie, E pour connecter. Limite de temps : 30 secondes.

Récompense : +15 réputation (bonus +5 si complété en moins de 15 s), article de journal dans l'inventaire.

Réputation et Quêtes Secondaires

Système de Réputation

Fichier : js/mecanicas/reputacion.js (74 lignes) — score de 0 à 100 avec 4 niveaux.

PlageNiveauCouleur de la Barre
0-24InconnuRouge
25-49ConnuJaune
50-74RespectéVert
75-100LégendaireOr

La réputation affecte le combat (bonus de patience initial) et s'affiche dans l'épilogue final. Gagnée par les victoires pacifistes (+15), les victoires par la force (+5), les mini-jeux (+15 chacun) et les actions écologiques (+10).

5 Quêtes Secondaires

Fichier : js/mecanicas/misiones-secundarias.js (89 lignes) — machine à états par quête.

QuêteDescriptionDéclencheur
BatúJouer au jeu de balle taïno avec HigüemotaParler à Higüemota dans l'Asentamiento II
Sauvetage du LamantinLibérer le lamantin + nettoyer le récifParler à la Dra. Sofía dans le Sanctuaire
Bonnes VibrationsCalibrer le magnétomètreParler à un PNJ à La Isabela
Full Metal ArcheologistProgrammer le robot sous-marinParler au biologiste dans le Sanctuaire
Weird ScienceRéparer l'équipement d'analyseParler au mentor dans le Laboratoire

Chaque quête progresse : non_découverte → découverte → en_cours → complétée. Le Journal de jeu (touche L) affiche tous les états de quête dans deux onglets : Histoire Principale (13 nœuds avec ✅/🔓/🔒) et Quêtes Secondaires (avec coches).

💾 Système de Sauvegarde

Fichier : js/motor/guardado.js (243 lignes) — persistance par localStorage.

Sauvegarde Automatique

Le jeu sauvegarde automatiquement en revenant à la carte du monde. « Continuer la partie » dans le menu principal restaure tout l'état et renvoie à la carte.

Données Sérialisées

Reconstruction des Compagnons

Les compagnons sont sauvegardés comme {tipo: 'magnoboot', activo: true} et reconstruits en instances réelles via _crearCompaneroBasico(tipo, activo) en utilisant les imports Magnoboot, Viralata et CemiMurcielago.

🌐 Carte de Référence (LeafletJS)

Répertoire : js/mapas/ (4 fichiers, ~700 lignes) — carte géographique réelle avec sites archéologiques.

Configuration

Centre : 19,0°N, -70,5°O (République Dominicaine). Zoom par défaut : 8. S'ouvre avec la touche R depuis n'importe quelle scène jouable (pas seulement la carte du monde). Tuiles Stadia Maps (6 couches esthétiques : Watercolor, Terrain, Toner, Dark, Smooth, OSM Bright) avec CARTO Voyager en solution de repli.

Couches de Données (76 sites réels)

CoucheIcôneNombre
Sites taïnos🗿16 (asentamientos, grottes, pétroglyphes en RD et Haïti)
Sites coloniaux🏰8 (La Isabela, Zone Coloniale, Cap-Haïtien, etc.)
Naufrages12 (Santa María 1492, San Miguel 1551, Concepción 1641, etc.)
Musées🏛30 (RD + Haïti)
Sites inexplorés🔍8 (visibles uniquement après le mini-jeu du robot)

Interaction

Marqueurs avec popup (nom + description) au clic. Voyage au clic : window._viajarANodo(id) pour un vol animé et changement de scène. État visuel : complété (bordure verte + luminosité), verrouillé (niveaux de gris + opacité 0,4), actif (bordure blanche).

🎬 Fins Multiples

Fichier : js/escenas/final-cinematica.js (673 lignes) — 5 fins + générique cinématographique.

Types de Fin

FinConditionTitre
Complète8 nœuds + 7 quêtes secondaires + plus de pacifiés que de violents« Légende de Quisqueya »
Pacifiste8 nœuds + plus de pacifiés, aucun violent« Gardien du Patrimoine »
Écologique3+ actions écologiques + aucune violence« Protecteur de l'Écosystème Marin »
SombrePlus de combats violents que de pacifiés« Le patrimoine mérite un autre chemin »
MuséeSolution par défaut« Conservateur de l'Histoire »

Séquence

5 étapes de texte avec avancement automatique (5-6 s chacune), saut avec E. Fonds thématiques par fin : dégradés dorés (complète/pacifiste), bleu marin avec bulles (écologique), rouge avec fractures (sombre), chaleureux avec point lumineux (musée). Niveau de réputation affiché dans l'épilogue.

Générique

Défilement vertical automatique à 40 px/s. Liste des 8 créateurs (les fous du robot), le Liceo Francés de Santo Domingo et l'année 2026. E pour accélérer/sauter.

🌍 Internationalisation

Répertoire : js/idiomas/ (4 fichiers, ~4 400 lignes).

Structure

3 fichiers de traduction (es.js, en.js, fr.js) avec ~1 100+ clés chacun, organisés en objets JavaScript imbriqués. Un gestionnaire idiomas.js (73 lignes) fournit :

Sections Principales

SectionContenu
menuTitres, options du menu principal
seleccionSélection du personnage
interfazHUD (vie, oxygène, inventaire), phrases de mort (10 variantes)
dialogosTous les dialogues par monde (grotte, village, isabela, colonial, aquatique, juridique, laboratoire, LFSD, fins)
combateActions et messages de combat
batu25 clés de mini-jeu (règles, faits, messages)
objetos32+ objets avec nom et description
inventarioInterface de l'inventaire
climaNoms des états météorologiques
guardadoChaînes du système de sauvegarde

Accès dans le Code

// Dans les scènes et mécaniques :
const texts = juego.idiomas.traducciones[juego.idiomas.idiomaActual];
const name = texts.menu.titulo;

// Ou avec l'accesseur par notation pointée :
const text = juego.idiomas.t('dialogos.cueva.petroSol');

🧑 Joueur (Pepito/Pepita)

Fichier : js/personajes/pepito.js (258 lignes).

Deux Modes de Déplacement

Propriétés Principales

PropriétéValeur
Dimensions28×32 px (plus étroit que la tuile de 32 px pour un passage plus facile)
Vie maximale100 PV
Genre'pepito' (masculin) ou 'pepita' (féminin)

Animation de Marche

Les jambes s'animent avec Math.sin(cuadroAnimacion * 5) * 3 — un mouvement sinusoïdal simulant les pas. Les bras avec Math.sin(cuadroAnimacion * 2) * 1. L'animation n'avance que quand esAnimando = true.

Sélection du Personnage

js/escenas/seleccion-personaje.js (291 lignes) : le sprite du jeu est affiché en échelle ×2,5 avec animation de marche en direct. Pepito est bleu (#4488ff) avec des cheveux en pétard ; Pepita est violette (#aa44ff) avec des tresses.

⚙️ Configuration et Constantes

Fichier : js/motor/configuracion.js (95 lignes) — point de configuration central.

ConstanteValeurUtilisation
ANCHO_JUEGO960Largeur du canvas en pixels
ALTO_JUEGO540Hauteur du canvas (16:9)
TAMANO_TILE32Taille standard d'une tuile
GRAVEDAD0,6Accélération verticale en mode plateforme
VELOCIDAD_JUGADOR3Pixels par image
FPS_OBJETIVO60Images par seconde
ESCALA_MINIMA0,5Échelle minimale du canvas
ESCALA_MAXIMA3,0Échelle maximale du canvas
CLAVE_GUARDADO'arclycee_guardado'Clé localStorage

Dimensions des Sprites

TypeLargeur × Hauteur
Joueur32 × 32
Compagnon24 × 24
Cemí16 × 16
PNJ32 × 32
Boss64 × 64
Grand Boss96 × 96
Objet16 × 16
Pétroglyphe48 × 48

📁 Fichiers Principaux par Taille

#FichierLignesResponsabilité
1santuario-manati.js2 905Sanctuaire : oxygène, requins, vedettes, écologie
2mundo-acuatico.js2 174Naufrage : méduses, tortues, baleines, combat
3sonido-procedural.js1 93160 effets audio générés par code
4zona-colonial.js1 923Zone Coloniale : PNJ, combat, activisme
5juego.js1 659Boucle de jeu, scènes, couches, notifications
6es.js1 523Traductions espagnoles
7fr.js1 472Traductions françaises
8en.js1 408Traductions anglaises
9cuevas-pomier.js1 340Plateforme en grotte avec effet de torche
10mundo-juridico.js1 335Aéroport : combat juridique, INTERPOL