Qual è il modo migliore per utilizzare requestAnimationFrame e frame rate fissi

4

Recentemente ho iniziato a usare l'HTML5- requestAnimationFrame -API molto sui siti web di animazione, specialmente dopo aver visto Jank Busters parlare. Questo sembra funzionare piuttosto bene e in realtà migliorare le prestazioni in molti casi.

Tuttavia, una domanda persiste ancora per me: quando si desidera utilizzare un'animazione che NON sia interamente calcolata (si pensi agli spritesheets per esempio) si dovrà mirare a una frequenza fotogrammi fissa. Ovviamente si potrebbe tornare a usare setInterval di nuovo, ma forse ci sono altri modi per affrontarlo.

I due modi in cui potrei pensare di usare requestAnimationFrame con una frequenza fotogrammi fissa sono:

var fps = 25; //frames per second

function animate(){

   //actual drawing goes here
   setTimeout(function(){
      requestAnimationFrame(animate);
   }, 1000 / fps)

}

animate();

o

var fps = 25; //frames per second

var lastExecution = new Date().getTime();

function animate(){

    var now = new Date().getTime();

    if ((now - lastExecution) > (1000 / fps)){
        //do actual drawing
        lastExecution = new Date().getTime();
    }

    requestAnimationFrame(animate);

}

animate();

Personalmente, opterei per la seconda opzione (la prima sembra barare), ma sembra essere più buggy in determinate situazioni.

Questo approccio vale davvero la pena (specialmente con frame rate bassi come 12.5)? Ci sono cose da migliorare? C'è un altro modo per affrontare questo?

    
posta m90 15.11.2012 - 11:02
fonte

2 risposte

2

L'animazione dovrebbe essere calcolata anche se il calcolo è interamente funzione del tempo. E in qualsiasi momento dovresti essere in grado di draw() un'immagine [animata] e sapere che stai ricevendo la cornice giusta. Vuoi qualcosa di simile, ma non necessariamente questo :

// whatever your "attributes" looks like, the point is you've given enough
// information to the constructor to find ordered frames in the image and know
// the framerate
function SpriteAnimation(image, attributes) {

  // you probably want a SpriteFrame "class" to populate here, based on whatever
  // existing code you use to extract frames from the sprite
  this.frames = [ SpriteFrame, SpriteFrame, ... ];
                         // ... getFramesFromImageAndAttributes(image, attributes)

  // if the animation is running, this is the time it started
  this.startTime = 0;

  // whatever your framerate is ... 
  this.fps = 25;         // getFPSFromAttributes(frame_attributes)

  // whether the animation loops infinitely
  this.loop = true;      // getLoopFlagFromAttributes(frame_attributes)

  // for canceling the animationframe request, if necessary
  this.animationFrameRequestId = null;

  // draw whichever frame should be visible *right now*
  this.draw = function() {

    // unconditionally show the first frame if the animation isn't running
    if (this.startTime == 0) {
      this.frames[0].draw();
      return;
    }

    // there may be a better and more accurate way to compute this ...
    var frame_duration = 1000 / this.fps;
    var now = (new Date()).getTime();
    var elapsed_time = now - this.startTime;
    var visible_frame = Math.floor(elapsed_time / frame_duration);

    if (visible_frame_number > frames.length) {
      if (!this.loop) {
        // we're past the end of the animation and we're not looping.
        // stop the animation.
        this.startTime = 0;
        visible_frame = 0;
      }
    }

    this.frames[visible_frame % frames.length].draw();

    if (this.startTime != 0) {
      var _t = this;
      requestAnimationFrame(_t.draw);
    }

  }

  this.animate = function() {
    this.startTime = (new Date()).getTime();
    var _t = this;
    requestAnimationFrame(_t.draw);
  }

  this.stop = function() {
    this.startTime = 0;
    if (this.animationFrameRequestId) {
      cancelAnimationFrame(this.animationFrameRequestId);
    }
  }

}

var a = new SpriteAnimation("/path/to/image.jpeg", {
  fps: 25,
  frame_width: 100,
  frame_height: 100,
  image_width: 1000,
  image_height: 10000
});
a.animate();

... O qualsiasi altra cosa.

    
risposta data 13.08.2013 - 19:55
fonte
0

Per animazioni senza interruzioni, anche gli sprite utilizzano la seconda opzione, con Date.now() . Non dimenticare

Return value

requestID is a long integer value that uniquely identifies the entry in the callback list. This is a non-zero value, but you may not make any other assumptions about its value. You can pass this value to window.cancelAnimationFrame() to cancel the refresh callback request.

(da MDN )

    
risposta data 16.11.2012 - 11:36
fonte

Leggi altre domande sui tag