◆ Portail Antalaha

Annuaire › Code ouvert

Baie d'Antalaha : diorama 3D animé jour et nuit

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/scene.js · 6.4 Ko

/* ==========================================================================
 * js/scene.js — L'ASSEMBLAGE DE LA SCÈNE 3D
 * --------------------------------------------------------------------------
 * Ce fichier ne dessine presque rien lui-même : il APPELLE les fabriques des
 * autres fichiers (mer, palmier, pirogue, ciel) et les place dans le diorama.
 * Il construit aussi l'île : une plage (disque de sable) et une colline à
 * deux bosses (deux demi-sphères).
 *
 * Il offre à main.js une interface très simple :
 *   scene.mettreAJour(t, dt, heure)  -> à chaque image
 *   scene.appliquerPalette(p)        -> quand l'heure change
 *
 * Dépend de : Zdog, Baie.CONFIG, Baie.QUALITE, Baie.tirerVersLeFond, et des
 * fabriques Baie.creerMer, creerPalmier, creerPirogue, creerCiel.
 * ========================================================================== */

(function () {
  'use strict';

  var TAU = Zdog.TAU;

  // ---- Constantes réglables -------------------------------------------------
  // Les palmiers : position au sol (x, z), hauteur, inclinaison, orientation,
  // graine. Ils sont placés AUTOUR de la colline, sur la plage (rayon ≈ 75).
  // Sur mobile, on n'utilise que les premiers de la liste.
  var PALMIERS = [
    { x: 58,  z: 28,  hauteur: 46, penche: 12,  orientation: 0.4,  graine: 3 },
    { x: -62, z: 20,  hauteur: 52, penche: -14, orientation: 2.5,  graine: 8 },
    { x: 34,  z: 58,  hauteur: 40, penche: 10,  orientation: 1.0,  graine: 15 },
    { x: -30, z: -62, hauteur: 50, penche: 12,  orientation: -0.5, graine: 21 },
    { x: 60,  z: -30, hauteur: 44, penche: -10, orientation: 3.8,  graine: 33 },
    { x: -10, z: 52,  hauteur: 36, penche: 8,   orientation: 2.0,  graine: 40 },
  ];

  /**
   * Construit l'île : plage + colline.
   *
   * @param {Zdog.Anchor} parent Où l'accrocher.
   * @returns {Object} { appliquerPalette(p) }
   */
  function creerIle(parent) {

    // 1) LA PLAGE MOUILLÉE : un grand disque couché, un peu plus large.
    //    Une Ellipse n'a qu'un `diameter` pour un cercle. Elle regarde vers z
    //    par défaut ; rotate x = TAU/4 la COUCHE (sa face regarde vers le haut).
    var plageMouillee = new Zdog.Ellipse({
      addTo: parent,
      diameter: 172,
      rotate: { x: TAU / 4 },
      translate: { y: 1 },
      fill: true,
      stroke: false,
      color: '#d9c48f',
    });
    // Juste après la mer (qui est à -1 000 000), avant tout le reste.
    Baie.tirerVersLeFond(plageMouillee, -500001);

    // 2) LA PLAGE SÈCHE : un disque un peu plus petit, posé dessus.
    var plage = new Zdog.Ellipse({
      addTo: parent,
      diameter: 152,
      rotate: { x: TAU / 4 },
      translate: { y: -0.5 },
      fill: true,
      stroke: false,
      color: '#f2deaa',
    });
    Baie.tirerVersLeFond(plage, -500000);

    // 3) LA COLLINE : deux demi-sphères (Hemisphere).
    //    Une Hemisphere a son dôme tourné vers z ; rotate x = TAU/4 le redresse
    //    vers le HAUT. Sa base est un disque dont la couleur est `backface`.
    //    stroke: false => bord net, sans contour.
    var colline1 = new Zdog.Hemisphere({
      addTo: parent,
      diameter: 104,
      translate: { x: -18, z: -14 },
      rotate: { x: TAU / 4 },
      stroke: false,
      color: '#6fcf5a',
      backface: '#f2deaa',
    });
    var colline2 = new Zdog.Hemisphere({
      addTo: parent,
      diameter: 64,
      translate: { x: 24, z: 6 },
      rotate: { x: TAU / 4 },
      stroke: false,
      color: '#6fcf5a',
      backface: '#f2deaa',
    });

    var tmp = [0, 0, 0];

    /** Recolore l'île selon la palette. */
    function appliquerPalette(p) {
      plage.color = p.css.sable;
      plageMouillee.color = Baie.Palette.nuancer(p.rgb.sable, -0.12, tmp);
      colline1.color = p.css.herbe;
      colline1.backface = p.css.sable;
      // La 2e bosse est un peu plus claire : elle reçoit plus de lumière.
      colline2.color = Baie.Palette.nuancer(p.rgb.herbe, 0.1, tmp);
      colline2.backface = p.css.sable;
    }

    return { appliquerPalette: appliquerPalette };
  }

  /**
   * Construit TOUTE la scène (île, mer, palmiers, pirogue, ciel).
   *
   * @param {Zdog.Illustration} illo  L'illustration à laquelle accrocher la scène.
   * @returns {Object} { monde, mettreAJour(t, dt, heure), appliquerPalette(p) }
   */
  function creerScene(illo) {
    var Q = Baie.QUALITE;

    // Le « monde » : une ancre qui contient tout. On la descend un peu pour
    // que le point de rotation (centre de l'illustration) soit au milieu de la
    // scène plutôt qu'au niveau de la mer.
    var monde = new Zdog.Anchor({
      addTo: illo,
      translate: { y: Baie.CONFIG.decalageVertical },
    });

    // L'ordre de création n'a pas d'importance pour l'affichage : Zdog trie
    // par profondeur (et nos astuces tirerVersLeFond gèrent mer et plage).
    var mer = Baie.creerMer(monde);
    var ile = creerIle(monde);

    // Les palmiers : une BOUCLE sur la liste de réglages, une fabrique par palmier.
    var palmiers = [];
    for (var i = 0; i < Math.min(Q.palmiers, PALMIERS.length); i++) {
      palmiers.push(Baie.creerPalmier(monde, PALMIERS[i]));
    }

    var pirogue = Baie.creerPirogue(monde, mer);
    var ciel = Baie.creerCiel(monde);

    /**
     * Fait avancer toute la scène d'une image. À appeler à chaque image.
     * AUCUNE création d'objet ici : seulement des nombres modifiés.
     *
     * @param {number} t      Temps d'animation (s). Ne progresse pas en pause.
     * @param {number} dt     Durée de l'image (s). Vaut 0 en pause.
     * @param {number} heure  Heure de la journée (0 à 24), pour placer soleil et lune.
     */
    function mettreAJour(t, dt, heure) {
      mer.mettreAJour(t);
      for (var i = 0; i < palmiers.length; i++) { palmiers[i].mettreAJour(t); }
      pirogue.mettreAJour(t, dt);
      ciel.mettreAJour(t, dt);
      ciel.placerAstres(heure);
    }

    /**
     * Applique une palette de couleurs à tous les éléments.
     * Appelée seulement quand l'heure a changé (pas à chaque image).
     * @param {Object} p Palette (Baie.Palette.calculer()).
     */
    function appliquerPalette(p) {
      mer.appliquerPalette(p);
      ile.appliquerPalette(p);
      for (var i = 0; i < palmiers.length; i++) { palmiers[i].appliquerPalette(p); }
      pirogue.appliquerPalette(p);
      ciel.appliquerPalette(p);
    }

    return { monde: monde, mettreAJour: mettreAJour, appliquerPalette: appliquerPalette };
  }

  Baie.creerScene = creerScene;
})();