Animazioni HTML5 più fluide con requestAnimationFrame



by   |  LETTURE 5166

Animazioni HTML5 più fluide con requestAnimationFrame

Per chi si è cimentato o sta per cimentarsi nello sviluppo di giochi o applicazioni HTML5 e javascript sarà utile sapere che esiste una nuova funzione in grado di gestire in modo più efficiente il timing delle animazioni.

In passato ci si basava sull’utilizzo della funzione setInterval in questo modo:

 function gameLoop() {          // Disegno la schermata  }  setInterval(gameLoop, 30);
In questo modo il browser esegue il redraw della schermata ogni 30 millesimi di secondo.

Un’altro metodo poteva consistere nell’uso di setTimeout():

 function gameLoop() {        setTimeout(gameLoop,30);        // Disegno la schermata } gameLoop();
Il problema fondamentale nell’uso di queste funzioni è che il browser esegue molte altre operazioni durante il loop e questo non garantisce che l’intervallo temporale venga mantenuto.

Bisogna anche dire che tutte le latenze relative alle funzioni interne al loop introducono ulteriori ritardi nell’esecuzione del ciclo compromettendo l’esatta sicronizzazione dei frame. Un’altro problema è relativo al fatto che i browser eseguono il refresh della finestra secondo un loro timing e questo sistema non garantisce nessun tipo di allineamento con le nostre applicazioni.

Il risultato è un’animazione poco fluida, con interruzioni ed eccessivo uso della CPU. Per fortuna in nostro aiuto arriva la funzione requestAnimationFrame la quale comunicando direttamente col browser cerca di mantenere un framerate di 60/fps (più che sufficiente a realizzare animazioni fluide) e non sovraccarica il sistema a livello di CPU.

Il suo utilizzo è molto semplice:

 function gameLoop() {        requestAnimationFrame(gameLoop);        // Disegno shermata } gameLoop();
Come si può notare manca la possibilità di impostare uno specifico intervallo di tempo.

Per farlo basta aggiungere alcune semplici righe di codice:

 var fps = 30; function gameLoop() {     setTimeout(function() {            requestAnimationFrame(gameLoop);         // Disegno schermata     }, 1000 / fps); }
Ecco fatto, semplice no ? Ora aggiungiamo un po di codice per mantenere la compatibilità tra browser:
 (function() {     var lastTime = 0;     var vendors = [´ms´, ´moz´, ´webkit´, ´o´];     for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {         window.requestAnimationFrame = window[vendors[x]+´RequestAnimationFrame´];         window.cancelAnimationFrame = window[vendors[x]+´CancelAnimationFrame´]                                    || window[vendors[x]+´CancelRequestAnimationFrame´];     }      if (!window.requestAnimationFrame)         window.requestAnimationFrame = function(callback, element) {             var currTime = new Date().getTime();             var timeToCall = Math.max(0, 16 - (currTime - lastTime));             var id = window.setTimeout(function() { callback(currTime + timeToCall); },               timeToCall);             lastTime = currTime + timeToCall;             return id;         };      if (!window.cancelAnimationFrame)         window.cancelAnimationFrame = function(id) {             clearTimeout(id);         }; }());
In questo modo possiamo utilizzare la funzione senza problemi.