Jiang Wen
Jiang Wen

Reputation: 57

When using requestAnimationFrame, how to make part of animation update faster

I am using requestAnimationFrame to make a game (game like a snake), and the frame update speed of the game is initially updated each second one time

It needs to update the "requestAnimationFrame" of this snake from a second each time to 0.5 second each time. Because of many snakes’ design and while a snake touches any item, it will get a speed-up situation for 10 seconds.

My question is how to maintain the main "requestAnimationFrame" (updated every second), and there is still another "requestAnimationFrame" (updated every 0.5 second)?

main requestAnimationFrame code

    let speed = 1;
    let lastRenderTime = 0;

    const doAnimation = function (currentTime) {

        window.requestAnimationFrame(doAnimation);

        const secondRender = (currentTime - lastRenderTime) / 1000;  // secondRender is used to control the update per second

        if (secondRender < 1 / speed) {
            return;
        }
        lastRenderTime = currentTime
    }

    window.requestAnimationFrame(doAnimation);

Upvotes: 0

Views: 225

Answers (2)

Ernesto Stifano
Ernesto Stifano

Reputation: 3130

requestAnimationFrame fire rate is usually around 60Hz. That is 60 calls per second, giving you a maximum theoretical precision of ~16ms (0.016s).

This means that inside you loop you can make things update at any rate above that. But why would you like to truncate precision?

The whole point of requestAnimationFrame is to know exactly when a repaint will happen and to pass information about your animation at the right time. As an example: if your snake has to move 1000px every second, why would you notify the browser about the update every second? Ideally you should update your view on every frame. So in this example, a 16px variation every 16ms.

Please see the following snippet and note that there are no conditionals, anywhere. But just continuous update.

Obviously final implementation would depend on your use case, but this is only the working principle.

const boxA = document.getElementById('boxA'); // DEMO
const boxB = document.getElementById('boxB'); // DEMO

let xA = 0; // DEMO
let xB = 0; // DEMO

const speedA = 80; // [px/s]
const speedB = 160; // [px/s]

let then = 0;

const animate = function (now) {
    window.requestAnimationFrame(animate);

    const delta = (now - then) / 1000;

    // A
    const a = speedA * delta;
    boxA.style.transform = `translateX(${xA += a}px)`; // DEMO
    
    // B
    const b = speedB * delta;
    boxB.style.transform = `translateX(${xB += b}px)`; // DEMO
    
    then = now
}

window.requestAnimationFrame(animate);
.container {
  display: flex;
  flex-direction: column;
}

#boxA,
#boxB {
  display: inline-block;
  height: 50px;
  width: 50px;
  transform: translateX(0);
}

#boxA {
  background-color: #ff0000;
}

#boxB {
  background-color: #0000ff;
}
<div class='container'>
  <span id='boxA'></span>
  <span id='boxB'></span>
</div>

Upvotes: 1

Kostas
Kostas

Reputation: 1903

let then, then2;
(function loop(delta) {
  then = then || delta;
  then2 = then2 || delta;
  
  let time = delta - then;
  let time2 = delta - then2;
  
  if (time > 1000) {
    then = delta;
    // in here every second
  }
  if (time2 > 500) {
    then2 = delta;
    // in here every 0.5 seconds
  }
  
  document.body.innerHTML = time.toFixed(2) + '<br>' + time2.toFixed(2);
  requestAnimationFrame(loop);
})();

Upvotes: 0

Related Questions