如何使用requestAnimationFrame控制幀率(fps)


fps一詞通常與影片和遊戲相關,在這些領域需要使用動畫。fps是每秒幀數的縮寫,表示螢幕每秒重新渲染的次數。

例如,影片是由連續的影像序列組成的。這意味著它以非常短的間隔顯示影像,以至於使用者無法察覺到它是逐幀顯示的。如果降低影片的fps,它看起來可能更像動畫而不是影片。因此,更高的fps通常能帶來更好的效果。基本上,fps告訴我們螢幕每秒應該更新多少次。

有時,我們需要使用JavaScript來控制fps。我們可以使用不同的方法,我們將在本教程中學習這些方法。

使用setTimeout()函式

setTimeout()函式以回撥函式作為第一個引數,時間間隔作為第二個引數。在這裡,我們可以每隔一段時間重新渲染螢幕來控制fps。

語法

使用者可以按照以下語法使用setTimeout()函式來控制fps。

setTimeout(() => {
   requestAnimationFrame(animate);
}, interval);

我們在上面的語法中使用requestAnimationFrame()方法呼叫了animate()函式。

步驟

  • 步驟1 − 定義totalFrames變數並初始化為零。它將記錄總幀數。

  • 步驟2 − 同樣,定義fps變數並存儲fps的值。

  • 步驟3 − 定義intervalOffps變數並將間隔儲存到其中。它儲存1000/fps,其中1000是毫秒,我們透過將其除以fps來獲得時間間隔。

  • 步驟4 − 將當前時間儲存在startTime變數中。

  • 步驟5 − 呼叫animate()函式。

  • 步驟5.1 − 使用setTimeout()函式在每個intervalOffps之後呼叫requestAnimationFrame()函式。

  • 步驟5.2 − 在setTimeout()函式的回撥函式中,使用者可以編寫程式碼來重新渲染螢幕或在Canvas上繪製形狀。

  • 步驟5.3 − 使用Date()物件獲取當前時間。從當前時間減去起始時間以獲得經過的時間。

  • 步驟5.4 − 使用數學函式,獲取總fps和總時間。

示例1

在下面的示例中,我們使用setTimeout()函式來控制fps。我們使用'3'作為fps的值。因此,我們的fps間隔等於1000/3。所以,我們將每隔1000/3毫秒呼叫一次requestAnimationFrame()方法。

<html>
<body>
   <h3> Using the <i> setTimeOut() method </i> to control the fps with requestAnimationFrame </h3>
   <div id="output"> </div>
   <script>
      let output = document.getElementById("output");
      // Initial frame count set to zero
      var totalFrames = 0;
      var current, consumedTime;
      
      // Set the fps at which the animation will run (say 10 fps)
      var fps = 3;
      var intervalOffps = 1000 / fps;
      var AfterTime = Date.now();
      var starting = AfterTime;
      animate();
      function animate() {
         setTimeout(() => {
         
            //  call the animate function recursively
            requestAnimationFrame(animate);
            
            // get current time
            current = Date.now();
            
            // get elapsed time since the last frame
            var elapsed = current - starting;
            
            //Divide elapsed time with frame count to get fps
            var currentFps =
            Math.round((1000 / (elapsed / ++totalFrames)) * 100) / 100;
            output.innerHTML = "Total elapsed time is equal to = " + Math.round((elapsed / 1000) * 100) / 100 + "<br>" + " secs @ ";
            output.innerHTML += currentFps + " fps.";
         }, intervalOffps);
      }
   </script>
</body>
</html>

使用Date()物件

我們可以使用Date()物件獲取當前時間和上一幀時間之間的差值。如果時間差超過幀間隔,我們將重新渲染螢幕。否則,我們將等待完成單幀。

語法

使用者可以按照以下語法使用時間間隔來控制fps。

consumedTime = current - AfterTime;
if (consumedTime > intervalOffps) {
   // rerender screen
}

在上面的語法中,消耗的時間是當前時間和上一幀完成時間之間的差值。

示例2

在下面的示例中,我們獲取當前幀和上一幀之間的時間差。如果時間差大於時間間隔,我們將重新渲染螢幕。

<html>
<body>
   <h3> Using the <i> Date() object </i> to control the fps with requestAnimationFrame. </h3>
   <div id = "output"> </div>
   <script>
      let output = document.getElementById("output");
      // Initial framecount set to zero
      var totalFrames = 0;
      var current, consumedTime;
      
      // Set the fps at which the animation will run (say 10 fps)
      var fps = 50;
      var intervalOffps = 1000 / fps;
      var AfterTime = Date.now();
      var starting = AfterTime;
      animate();
      function animate() {
      
         // use date() object and requestAnimationFrame() to control fps
         requestAnimationFrame(animate);
         current = Date.now();
         consumedTime = current - AfterTime;
         
         // if the consumed time is greater than the interval of fps
         if (consumedTime > intervalOffps) {
         
            // draw on canvas here
            AfterTime = current - (consumedTime % intervalOffps);
            var elapsed = current - starting;
            
            //Divide elapsed time with frame count to get fps
            var currentFps =
            Math.round((1000 / (elapsed / ++totalFrames)) * 100) / 100;
            output.innerHTML = "Total elapsed time is equal to = " + Math.round((elapsed / 1000) * 100) / 100 + "<br>" + " secs @ ";
            output.innerHTML += currentFps + " fps.";
         }
      }
   </script>
</body>
</html>

示例3

在下面的示例中,使用者可以使用輸入範圍設定fps。之後,當用戶點選按鈕時,它將執行startAnimation()函式,該函式設定fps間隔並呼叫animate()函式。animate()函式呼叫drawShape()函式在畫布上繪製形狀並控制fps。

在這裡,我們使用了一些方法在畫布上繪製形狀。使用者可以使用輸入範圍更改fps,嘗試動畫形狀並觀察動畫中的差異。

<html>
<body>
   <h3>Using the <i> Date() object </i> to control the fps with requestAnimationFrame. </h3>
   <!-- creating an input range for fps -->
   <input type = "range" min = "1" max = "100" value = "10" id = "fps" />
   <button onclick = "startAnimation()"> Animate </button> <br><br>
   <!-- canvas to draw shape -->
   <canvas id = "canvas" width = "250" height = "250"> </canvas>
   <script>
      let canvas = document.getElementById("canvas");
      let context = canvas.getContext("2d");
      let animation;
      let intervalOffps, current, after, elapsed;
      let angle = 0;
      // drawing a sha[e]
      function drawShape() {
         context.save();
         context.translate(100, 100);
         
         // change angle
         context.rotate(Math.PI / 180 * (angle += 11));
         context.moveTo(0, 0);
         
         // draw line
         context.lineTo(250, 250);
         context.stroke();
         context.restore();
         
         // stop animation
         if (angle >= 720) {
            cancelAnimationFrame(animation);
         }
      }
      function animate() {
      
         // start animation and store its id
         animation = requestAnimationFrame(animate);
         current = Date.now();
         elapsed = current - after;
         
         // check if elapsed time is greater than interval, if yes, draw shape again
         if (elapsed > intervalOffps) {
            after = current - (elapsed % intervalOffps);
            drawShape();
         }
      }
      function startAnimation() {
      
         // get fps value from input
         let fpsInput = document.getElementById("fps");
         let fps = fpsInput.value;
         
         // calculate interval
         intervalOffps = 1000 / fps;
         after = Date.now();
         requestAnimationFrame(animate);
      }
   </script>
</body>
</html>

更新於:2023年5月4日

877 次瀏覽

啟動你的職業生涯

透過完成課程獲得認證

開始學習
廣告
© . All rights reserved.