◆ Portail Antalaha

Annuaire › Code ouvert

Pirogue d'Antalaha - jeu de vanille (p5.js)

tutorial · Voir le site ↗
Connectez-vous pour copier ce site

Code publié par son auteur, en lecture seule. « Copier dans mon espace » crée un nouveau site à vous (non publié) que vous pouvez modifier librement.

js/pirogue.js · 6.3 Ko

/* ============================================================
   pirogue.js - la classe Pirogue (le joueur)
   ============================================================
   Une CLASSE est un "moule" : elle décrit à la fois les DONNÉES
   d'un objet (position, vitesse...) et ses ACTIONS (se déplacer,
   se dessiner...). `new Pirogue()` fabrique un objet à partir du moule.

   Vue du dessus : la pirogue est dessinée pointe vers le HAUT, avec
   son balancier (le flotteur latéral des pirogues malgaches).
   ============================================================ */

class Pirogue {

  /* constructor : appelé par `new Pirogue()`. */
  constructor() {
    this.larg = PIROGUE.largeur;
    this.long = PIROGUE.longueur;
    this.y = PIROGUE.y;
    this.reinitialiser();
  }

  /* ----------------------------------------------------------
     reinitialiser()
     But : remettre la pirogue au centre pour une nouvelle partie.
     ---------------------------------------------------------- */
  reinitialiser() {
    this.x = LARGEUR_JEU / 2;
    this.vx = 0;                 // vitesse horizontale mesurée (pour l'inclinaison)
    this.inclinaison = 0;        // angle d'inclinaison en radians
    this.invulnerable = 0;       // secondes d'invulnérabilité restantes
    this.tempsPagaie = 0;        // sert à animer la pagaie
  }

  /* ----------------------------------------------------------
     limites()
     But : donner les positions x minimale et maximale permises,
           pour rester sur l'eau (le balancier dépasse à droite).
     Retour : {min, max}
     ---------------------------------------------------------- */
  limites() {
    return { min: RIVE + 22, max: LARGEUR_JEU - RIVE - 44 };
  }

  /* ----------------------------------------------------------
     mettreAJour(dt, direction, cibleX)
     But : déplacer la pirogue.
     Paramètres :
       dt        : secondes écoulées depuis la dernière image
       direction : -1 (gauche), 0 (rien), +1 (droite) : clavier
       cibleX    : abscisse du doigt (monde logique) ou null : tactile
     Le clavier est prioritaire sur le doigt.
     ---------------------------------------------------------- */
  mettreAJour(dt, direction, cibleX) {
    const xAvant = this.x;

    if (direction !== 0) {
      // Clavier : déplacement = vitesse x temps.
      this.x += direction * PIROGUE.vitesseClavier * dt;
    } else if (cibleX !== null) {
      // Tactile : on se rapproche du doigt, mais pas plus vite que la
      // vitesse maximale (constrain borne l'écart parcouru à chaque image).
      const pasMax = PIROGUE.vitesseTactile * dt;
      this.x += constrain(cibleX - this.x, -pasMax, pasMax);
    }

    // On empêche de sortir de l'eau.
    const lim = this.limites();
    this.x = constrain(this.x, lim.min, lim.max);

    // Vitesse réelle (distance / temps) ; on évite de diviser par zéro.
    this.vx = dt > 0 ? (this.x - xAvant) / dt : 0;

    // Inclinaison : la pirogue "penche" dans le sens du déplacement.
    // lerp() adoucit le changement pour éviter un mouvement saccadé.
    const inclinaisonVoulue = constrain(this.vx * 0.0007, -0.3, 0.3);
    this.inclinaison = lerp(this.inclinaison, inclinaisonVoulue, 0.2);

    this.tempsPagaie += dt;
    if (this.invulnerable > 0) this.invulnerable -= dt;
  }

  /* ----------------------------------------------------------
     boite()
     But : rectangle de collision (un peu plus petit que le dessin,
           c'est plus agréable pour le joueur).
     Retour : {x, y, l, h}  (x, y = coin haut-gauche)
     ---------------------------------------------------------- */
  boite() {
    return { x: this.x - 9, y: this.y - 30, l: 18, h: 60 };
  }

  /* ----------------------------------------------------------
     dessiner()
     But : dessiner la pirogue.
     Pendant l'invulnérabilité, elle CLIGNOTE (une image sur deux
     n'est pas dessinée).
     ---------------------------------------------------------- */
  dessiner() {
    if (this.invulnerable > 0 && Math.floor(this.invulnerable * 10) % 2 === 0) return;

    const L = this.long;
    const W = this.larg;
    const rebond = Math.sin(this.tempsPagaie * 3) * 1.5;   // léger mouvement de houle

    push();
    translate(this.x, this.y + rebond);     // l'origine (0,0) devient le centre de la pirogue
    rotate(this.inclinaison);               // puis on incline tout le dessin

    // --- Sillage derrière la pirogue (deux traînées en V) ---
    stroke(255, 255, 255, 120);
    strokeWeight(3);
    strokeCap(ROUND);
    line(-4, L * 0.45, -16, L * 0.45 + 34);
    line(4, L * 0.45, 16, L * 0.45 + 34);

    // --- Balancier : deux bras + un flotteur long, sur le côté droit ---
    stroke(COULEURS.coqueContour);
    strokeWeight(3);
    line(W * 0.35, -L * 0.18, W * 1.55, -L * 0.18);
    line(W * 0.35, L * 0.18, W * 1.55, L * 0.18);
    fill(COULEURS.balancier);
    strokeWeight(2);
    ellipse(W * 1.55, 0, W * 0.5, L * 0.72);

    // --- Coque : une forme fermée faite de deux courbes de Bézier ---
    // bezierVertex(cx1, cy1, cx2, cy2, x, y) : courbe vers (x, y) avec 2 points de contrôle.
    fill(COULEURS.coque);
    stroke(COULEURS.coqueContour);
    strokeWeight(2);
    beginShape();
    vertex(0, -L / 2);                                        // proue (pointe avant)
    bezierVertex(W * 0.95, -L * 0.2, W * 0.9, L * 0.3, 0, L / 2);       // côté droit jusqu'à la poupe
    bezierVertex(-W * 0.9, L * 0.3, -W * 0.95, -L * 0.2, 0, -L / 2);    // côté gauche en retour
    endShape(CLOSE);

    // Intérieur de la pirogue (plus sombre)
    noStroke();
    fill(COULEURS.coqueInterieur);
    ellipse(0, 0, W * 0.8, L * 0.62);

    // --- Pagaie (à gauche), qui balance avec le temps ---
    push();
    translate(-W * 0.3, -2);
    rotate(Math.sin(this.tempsPagaie * 6) * 0.35);
    stroke(COULEURS.pagaie);
    strokeWeight(3);
    line(0, 0, -W * 0.9, 18);
    noStroke();
    fill(COULEURS.pagaie);
    ellipse(-W * 0.95, 20, 6, 14);
    pop();

    // --- Le pagayeur vu du dessus : épaules + chapeau de paille ---
    noStroke();
    fill('#2f6f8f');
    ellipse(0, 0, W * 0.85, W * 0.45);
    fill(COULEURS.chapeau);
    stroke('#b89c3c');
    strokeWeight(1.5);
    circle(0, -2, W * 0.85);
    noFill();
    circle(0, -2, W * 0.4);

    pop();   // fin du repère de la pirogue : retour au repère normal
  }
}