◆ 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/obstacle.js · 4.8 Ko

/* ============================================================
   obstacle.js - la classe Obstacle (rochers et vagues)
   ============================================================
   Un seul moule pour deux sortes d'obstacles, distingués par la
   propriété `type` :
     'rocher' : un rocher à fleur d'eau, immobile par rapport à l'eau ;
     'vague'  : une vague déferlante, large, qui dérive un peu de côté.
   Toucher un obstacle fait perdre une vie.
   ============================================================ */

class Obstacle {

  /* ----------------------------------------------------------
     constructor(type, x, y)
     Paramètres :
       type : 'rocher' ou 'vague'
       x, y : position de départ (centre)
     ---------------------------------------------------------- */
  constructor(type, x, y) {
    this.type = type;
    this.x = x;
    this.y = y;
    this.mort = false;             // passe à true après une collision

    if (type === 'rocher') {
      this.rayon = random(18, 28);
      this.rx = this.rayon;        // demi-largeur (pour éviter les chevauchements au spawn)
      this.vx = 0;
      // Forme irrégulière : 9 sommets autour du centre, chacun à une
      // distance un peu différente. On les calcule UNE fois (pas à chaque image).
      this.sommets = [];
      const n = 9;
      for (let i = 0; i < n; i++) {
        const a = i * TWO_PI / n;
        const r = this.rayon * random(0.8, 1.15);
        this.sommets.push({ x: cos(a) * r, y: sin(a) * r });
      }
    } else {
      this.largeur = random(70, 110);
      this.rx = this.largeur / 2;
      this.vx = random(-25, 25);   // dérive latérale lente (unités par seconde)
    }
  }

  /* ----------------------------------------------------------
     mettreAJour(dt, vitesse)
     But : déplacer l'obstacle avec le défilement de l'eau.
     Paramètres : dt = secondes écoulées ; vitesse = vitesse de l'eau
     ---------------------------------------------------------- */
  mettreAJour(dt, vitesse) {
    this.y += vitesse * dt;
    if (this.type === 'vague') {
      this.x += this.vx * dt;
      // Rebond sur les rives : on inverse la vitesse horizontale.
      const gauche = RIVE + 8 + this.rx;
      const droite = LARGEUR_JEU - RIVE - 8 - this.rx;
      if (this.x < gauche || this.x > droite) {
        this.vx = -this.vx;
        this.x = constrain(this.x, gauche, droite);
      }
    }
  }

  /* estSorti() : true si l'obstacle est passé sous l'écran. */
  estSorti() {
    return this.y > HAUTEUR_JEU + 60;
  }

  /* ----------------------------------------------------------
     boite()
     But : rectangle de collision (légèrement plus petit que le dessin).
     Retour : {x, y, l, h}
     ---------------------------------------------------------- */
  boite() {
    if (this.type === 'rocher') {
      const d = this.rayon * 1.5;
      return { x: this.x - d / 2, y: this.y - d / 2, l: d, h: d };
    }
    return { x: this.x - this.largeur / 2 + 4, y: this.y - 18, l: this.largeur - 8, h: 20 };
  }

  /* dessiner() : appelle le bon dessin selon le type. */
  dessiner() {
    if (this.type === 'rocher') this.dessinerRocher();
    else this.dessinerVague();
  }

  /* ----------------------------------------------------------
     dessinerRocher()
     But : un anneau d'écume, puis le rocher (polygone gris) avec
           une zone claire en haut à gauche (la lumière).
     ---------------------------------------------------------- */
  dessinerRocher() {
    push();
    translate(this.x, this.y);

    // Écume autour du rocher
    noStroke();
    fill(255, 255, 255, 110);
    ellipse(0, 2, this.rayon * 3, this.rayon * 2.6);

    // Rocher : polygone fermé
    fill(COULEURS.rocher);
    stroke('#3f4348');
    strokeWeight(2);
    beginShape();
    for (const s of this.sommets) vertex(s.x, s.y);
    endShape(CLOSE);

    // Reflet de lumière : même forme, plus petite, décalée et plus claire
    noStroke();
    fill(COULEURS.rocherClair);
    beginShape();
    for (const s of this.sommets) vertex(s.x * 0.55 - 3, s.y * 0.55 - 4);
    endShape(CLOSE);
    pop();
  }

  /* ----------------------------------------------------------
     dessinerVague()
     But : une vague déferlante : demi-ellipse bleue + crête blanche.
     arc(x, y, l, h, début, fin, mode) : de PI à TWO_PI on obtient la
     moitié HAUTE de l'ellipse.
     ---------------------------------------------------------- */
  dessinerVague() {
    push();
    translate(this.x, this.y);
    noStroke();
    fill(COULEURS.vague);
    arc(0, 0, this.largeur, 46, PI, TWO_PI, CHORD);

    noFill();
    stroke(255);
    strokeWeight(5);
    strokeCap(ROUND);
    arc(0, 0, this.largeur, 46, PI, TWO_PI);          // crête d'écume
    strokeWeight(2);
    stroke(255, 255, 255, 170);
    arc(0, 4, this.largeur * 0.7, 28, PI + 0.2, TWO_PI - 0.2);   // 2e ligne d'écume
    pop();
  }
}