使用requestAnimationFrame时,如何让部分动画更新更快

问题描述

我正在使用requestAnimationFrame做一个游戏(像蛇一样的游戏),游戏的帧更新速度最初是每秒更新一次

它需要将这条蛇的“requestAnimationFrame”从每次1秒更新到每次0.5秒。由于很多蛇的设计,当蛇接触任何物品时,它会获得10秒的加速情况。

我的问题是如何维护主“requestAnimationFrame”(每秒更新一次),还有另一个“requestAnimationFrame”(每0.5秒更新一次)?

主要 requestAnimationFrame 代码

function firstButton() {
    var btn = document.createElement('button');
    btn.className = 'newButton';
    btn.innerHTML = 'hey';

    document.getElementById('messageContainer').appendChild(btn);
}

function secondButton() {
    var btn = document.createElement('button');
    btn.className = 'newButton';
    btn.innerHTML = 'Pssst';

    document.getElementById('messageContainer').appendChild(btn);
}

function thirdButton() {
    var btn = document.createElement('button');
    btn.className = 'newButton';
    btn.innerHTML = 'How have you been here?';

    document.getElementById('messageContainer').appendChild(btn);
}

function fourthButton() {
    var btn = document.createElement('button');
    btn.className = 'newButton';
    btn.innerHTML = 'I have got something to show you';

    document.getElementById('messageContainer').appendChild(btn);
}

function fifthButton() {
    var btn = document.createElement('button');
    btn.className = 'newButton';
    btn.innerHTML = 'Wanna See?';

    document.getElementById('messageContainer').appendChild(btn);
}

setTimeout(() => {
    firstButton();
},3000);

setTimeout(() => {
    secondButton();
},5000);

setTimeout(() => {
    thirdButton();
},7000);

setTimeout(() => {
    fourthButton();
},10000);

setTimeout(() => {
    fifthButton();
},12000);

function hideDots() {
    document.getElementById('Text').style.display = "none";
}



setTimeout(() => {
    hideDots();
},2500);

解决方法

requestAnimationFrame 射速通常在 60Hz 左右。即每秒 60 次调用,理论上的最大精度约为 16 毫秒(0.016 秒)。

这意味着在循环内部,您可以以高于此的任何速率更新内容。但是为什么要截断精度呢?

requestAnimationFrame 的全部意义在于准确知道何时会发生重绘并在正确的时间传递有关动画的信息。举个例子:如果你的蛇必须每秒移动 1000 像素,你为什么要每秒通知浏览器更新?理想情况下,您应该在每一帧上更新您的视图。所以在这个例子中,每 16ms 有一个 16px 的变化。

请查看以下代码片段,并注意任何地方都没有条件。但只是不断更新。

显然,最终实现将取决于您的用例,但这只是工作原理。

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>

,

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);
})();