◆ Portail Antalaha

Annuaire › Code ouvert

Maison 3D pour une agence immobilière

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/camera.js · 4.5 Ko

/* ==========================================================================
 * js/camera.js — LA « CAMÉRA » : vues, transitions douces, rotation auto
 * --------------------------------------------------------------------------
 * Zdog n'a pas de caméra : pour changer de point de vue, on FAIT TOURNER LA
 * SCÈNE ENTIÈRE (illo.rotate). Ce fichier gère trois comportements :
 *
 *   1. allerVers('face' | 'cote' | 'dessus') : une transition animée avec
 *      easeInOut (démarrage et arrivée en douceur) ;
 *   2. basculerAuto() : une rotation continue autour de la maison ;
 *   3. arreter() : on coupe tout (appelé quand l'utilisateur glisse).
 *
 * La caméra ne dessine rien : on appelle camera.mettreAJour(dt) à chaque
 * image depuis la boucle d'animation (main.js).
 *
 * Dépend de : Zdog, Maison.VUES, Maison.CAMERA, Maison.INCLINAISON_AUTO.
 * ========================================================================== */

(function () {
  'use strict';

  var TAU = Zdog.TAU;

  /**
   * Fabrique une caméra pour une illustration.
   *
   * @param {Zdog.Illustration} illo  La scène à faire tourner.
   * @param {function(string)} [quandVueChange]  Rappel appelé avec un texte
   *        décrivant l'état (« face », « rotation automatique »…).
   * @returns {Object} La caméra, avec ses méthodes.
   */
  function creerCamera(illo, quandVueChange) {
    var reglages = Maison.CAMERA;

    // L'état de la caméra. On le réutilise tout le temps : AUCUN nouvel objet
    // n'est créé dans la boucle d'animation (bon pour les performances).
    var etat = {
      auto: false,        // rotation automatique active ?
      enTransition: false,
      t: 0,               // progression de la transition, de 0 à 1
      departX: 0, departY: 0,
      arriveeX: 0, arriveeY: 0,
    };

    /** Prévient l'interface du nouvel état, si un rappel a été fourni. */
    function annoncer(texte) {
      if (quandVueChange) { quandVueChange(texte); }
    }

    /**
     * Lance une transition douce vers une des vues de Maison.VUES.
     * @param {string} cle  'face', 'cote' ou 'dessus'.
     */
    function allerVers(cle) {
      var vue = Maison.VUES[cle];
      if (!vue) { return; }
      etat.auto = false;
      etat.enTransition = true;
      etat.t = 0;
      etat.departX = illo.rotate.x;
      etat.departY = illo.rotate.y;
      etat.arriveeX = vue.x;

      // CHEMIN LE PLUS COURT : si la scène a déjà tourné de 5 tours, on ne
      // veut pas la faire revenir en arrière de 5 tours ! Zdog.modulo()
      // ramène l'écart dans l'intervalle [-TAU/2 ; +TAU/2] (un demi-tour max).
      var ecart = Zdog.modulo(vue.y - illo.rotate.y + TAU / 2, TAU) - TAU / 2;
      etat.arriveeY = illo.rotate.y + ecart;

      annoncer('vue de ' + vue.nom);
    }

    /** Active ou coupe la rotation automatique. @returns {boolean} le nouvel état. */
    function basculerAuto() {
      etat.auto = !etat.auto;
      etat.enTransition = false;
      annoncer(etat.auto ? 'rotation automatique' : 'vue libre');
      return etat.auto;
    }

    /** Coupe transition et rotation auto (l'utilisateur prend la main). */
    function arreter() {
      etat.auto = false;
      etat.enTransition = false;
      annoncer('vue libre');
    }

    /**
     * À appeler à chaque image.
     * @param {number} dt Temps écoulé depuis l'image précédente, en secondes.
     */
    function mettreAJour(dt) {
      if (etat.enTransition) {
        etat.t += dt / reglages.dureeTransition;
        var alpha = Math.min(etat.t, 1);
        // easeInOut transforme un avancement linéaire (0 -> 1) en avancement
        // « doux » : lent au début, rapide au milieu, lent à la fin.
        // Le 2e paramètre (3) est la puissance : plus grand = plus marqué.
        var doux = Zdog.easeInOut(alpha, 3);
        illo.rotate.x = Zdog.lerp(etat.departX, etat.arriveeX, doux);
        illo.rotate.y = Zdog.lerp(etat.departY, etat.arriveeY, doux);
        if (alpha >= 1) { etat.enTransition = false; }
      } else if (etat.auto) {
        illo.rotate.y += reglages.vitesseAuto * dt;                  // tourne en continu
        // L'inclinaison se rapproche doucement de la valeur de confort.
        illo.rotate.x += (Maison.INCLINAISON_AUTO - illo.rotate.x) * Math.min(dt * 2, 1);
      }
    }

    return {
      allerVers: allerVers,
      basculerAuto: basculerAuto,
      arreter: arreter,
      mettreAJour: mettreAJour,
      estAuto: function () { return etat.auto; },
    };
  }

  Maison.creerCamera = creerCamera;
})();