Интервал HTML Canvas vs RequestAnimationFrame

Итак, может быть, полный мозг. Синтаксис для setInterval() довольно ясен. Сделайте что-нибудь каждые x миллисекунды. Как это лучше всего перевести на использование requestAnimationFrame()?

У меня около 300 объектов, и каждый из них должен выполнять последовательность анимации с определенным интервалом (каждые 8, 6, 2 и т.д.)? Как я могу добиться этого, используя requestAnimationFrame(), который вызывается ~ 60 раз в секунду? Вероятно, есть легкий ответ, я просто, для жизни меня, не могу понять.

Ответы

Ответ 1

requestAnimationFrame довольно низкий уровень, он просто делает то, что вы уже сказали: грубо получилось вызывается со скоростью 60 кадров в секунду (при условии, что браузер не отстает от этого темпа). Таким образом, вам обычно нужно что-то создавать поверх этого, подобно движку игры, в котором есть игровой цикл.

В моем игровом движке у меня есть это (парафазное/упрощенное здесь):

window.requestAnimationFrame(this._doFrame);

...

_doFrame: function(timestamp) {
     var delta = timestamp - (this._lastTimestamp || timestamp);

     for(var i = 0, len = this.elements.length; i < len; ++i) {
         this.elements[i].update(delta);
     }

     this._lastTimestamp = timestamp;

     // I used underscore.js 'bindAll' to make _doFrame always
     // get called against my game engine object
     window.requestAnimationFrame(this._doFrame);
 }

Тогда каждый элемент моего игрового движка знает, как обновить себя. В вашем случае каждый элемент, который должен обновлять каждые 2, 6, 8 секунд, должен отслеживать, сколько времени прошло и обновить соответственно:

update: function(delta) {
     this.elapsed += delta;

     // has 8 seconds passed?
     if(this.elapsed >= 8000) {
          this.elapsed -= 8000;  // reset the elapsed counter
          this.doMyUpdate(); // whatever it should be
     }
 }

API холста вместе с requestAnimationFrame довольно низкий, они являются строительными блоками для таких вещей, как анимация и игровые движки. Если возможно, я попытаюсь использовать существующий, например cocos2d-js, или что-то еще там в эти дни.

Ответ 2

Чтобы заставить requestAnimationFrame придерживаться определенного FPS, вы можете использовать оба сразу!

var fps = 15;
function draw() {
    setTimeout(function() {
        requestAnimationFrame(draw);
        // Drawing code goes here
    }, 1000 / fps);
}

Немного странно, но не самая странная вещь в мире.

Вы также можете использовать requestAnimationFrame не с FPS, а с прошедшим временем, чтобы рисовать объекты, которые необходимо обновить, в зависимости от разницы во времени с момента последнего вызова:

var time;
function draw() {
    requestAnimationFrame(draw);
    var now = new Date().getTime(),
        dt = now - (time || now);

    time = now;

    // Drawing code goes here... for example updating an 'x' position:
    this.x += 10 * dt; // Increase 'x' by 10 units per millisecond
}

Эти два фрагмента находятся в этой прекрасной статье, в которой содержатся дополнительные сведения.

Хороший вопрос кстати! Я не думаю, что видел, что это тоже ответили на SO (и я здесь слишком много)