Content

Arf… il y avait dans Processing une super fonction delay(), et elle n’est actuellement pas du tout supportée dans Processing.js…

J’ai donc tâché de voir ce qu’on pouvait faire en Javascript pur, en particulier avec setTimeout().
Et bien non seulement setTimeout() permet de remplacer delay(), mais elle ouvre aussi des possibilités que je n’avais encore rencontré dans aucun langage !

Une fonction à prendre avec des pincettes malgré tout, voici donc quelques explications…

3 syntaxes de base pour la fonction Javascript native setTimeout() :

// syntaxe 1
setTimeout(function(){ ... }, 2000); // le temps est indiqué en millisecondes 

// syntaxe2
setTimeout(maFonction, 2000); // pb : pas facile d'envoyer des paramètres pour la fonction

// syntaxe 3
setTimeout("maFonction(mesParams);", 2000); // du code entre guillemets :)

La syntaxe 3 permet donc carrément de mettre en attente un bloc de code

…fonction(s), liste(s) d’instructions complexes, etc, tout ce qu’on veut comme code pour peu que ce soit entre guillemets et qu’on évite les sauts de lignes dans le code (Javascript gère très mal les sauts de lignes sur les variables de type String).
Si vous en voulez, vous utiliserez les n .
Et si vous avez besoin d’utiliser  » ou ‘ et bien préférez  » et ‘ dans le code…

Le code qu’on fournit au format texte/String ne sera exécuté et interprété que plus tard… et en attendant il ne pèse quasiment rien en mémoire.

Pour cette même raison la fonction setTimeout() n’utilise presque aucune ressource du processeur, on peut donc en user et en abuser :)

La où ça se corse, c’est lorsqu’on souhaite reporter l’exécution d’un code qui fait appel à une fonction d’une classe objet

Et oui ! Car si on fait depuis une classe :

setTimeout("this.goRandom();", 2000);

Au moment de l’interprétation du code (2 secondes plus tard), Javascript ne saura plus du tout à quoi this s’adresse !

La meilleure façon de palier au problème c’est d’ajouter une méthode this.delay() dans les classes qui en ont besoin !

C’est très pratique, car du même coup on peut exprimer le délai en secondes comme avec Processing (et non en millisecondes), et comme avec les Tweens.
Ca permet aussi de résoudre ce problème de cible perdue, et plus encore comme on le verra plus loin !

Pour une classe Snake, dont on aurait listé les occurences dans le tableau listeSnakes (dans le setup du sketch principal), la méthode sera :

Snake = new Class({
   initialize : function(_canvas, _id, _x, _y){
      this.id = id_; // id c'est le numéro de l'objet dans la liste listeSnakes
      ...
   },
   delay : function(codeString, sec){
    codeString = str_replace(codeString, 'this', "listeSnakes["+this.id+"]");
      setTimeout(codeString, sec*1000);
   }
});

L’astuce est très simple : on remplace automatiquement tous les « this » rencontrés (dans le code au format texte) par l’identifiant de l’objet « en dur » depuis la liste des objets…

« this. » -> « listeSnakes[64]. »

Ca fonctionne, du coup, sur n’importe quel code :

this.delay("this.goRandom();", 2);
// ou encore
this.delay("$('#div.test').hide();", 2);

Aucun problème de syntaxe, tout est centralisé, avec une utilisation hyper simplifiée :)

Et on peut faire encore mieux…

En plus des 3 syntaxes de setTimeout(), il y a aussi 2 façons distinctes de l’utiliser :

// façon libre : autant de setTimeout qu'on veut, qui s'exécuteront tous en parallèle
setTimeout("maFonction(mesParams);", 2000);

// façon ciblée : chaque setTimeout est injecté dans une variable...
wait1 = setTimeout("maFonction(mesParams);", 2000);

// ...on peut alors en prendre le contrôle plus tard pour l'arrêter
clearTimeout(wait1);

A partir de là on peut donc imaginer que chaque objet de la classe ait son « canal » de setTimeout(), dans lequel on n’aura qu’un seul setTimeout à la fois, le dernier appelé écrasant le précédent qui ne sera jamais exécuté.

Très pratique pour une navigation web, on peut aussi avoir des actions reportées à plus tard dans le cadre d’une animation, et les effacer pour recombiner les éléments à l’écran quand on change de page…

En fait on peut faire encore plus mieux : cumuler les 2 modes d’utilisation dans un seul outil, avec la détection des this, à utiliser comme on le souhaite suivant ce qu’on veut faire !

delay : function(codeString, sec){
   codeString = str_replace(codeString, 'this', "listeSnakes["+this.id+"]");
   delayed = setTimeout(codeString, sec*1000);
   return delayed;
},

dès lors on a accès aux 2 modes :

// mode libre, avec superposition de tous les delays
this.delay("this.goRandom();", 2);

// mode ciblé, un seul delay à la fois
clearInterval(effet1);
effet1 = this.delay("this.goRandom();", 2);

Avec ça on peut donc « séquencer » ses animations, et enchainer les effets dans le temps :)