JS:指定FPS幀頻,requestAnimationFrame播放動畫

來源:互聯網
上載者:User

標籤:style   blog   color   strong   io   for   

Flash製作動畫,最基礎的概念就是幀,但在Flash中,幀頻的控制比較簡單,只需要編譯前指定一下目標幀頻就可以了。

實際運行時,不需要我們關心定時器的問題,flash player會定時觸發EnterFrame訊息,推動Movieclip播放。

在js這一側,需要我們設定一個定時器,並推動相應的繪製邏輯執行。

 

最簡單:

var FPS = 60;setInterval(draw, 1000/FPS);

 

這個簡單做法,如果draw帶有大量邏輯計算,導致計算時間超過幀等待時間時,將會出現丟幀。除外,如果FPS太高,超過了當時瀏覽器的重繪頻率,將會造成計算浪費,例如瀏覽器實際才重繪2幀,但卻計算了3幀,那麼有1幀的計算就浪費了。

 

成熟做法:

引入requestAnimationFrame,這個方法是用來在頁面重繪之前,通知瀏覽器調用一個指定的函數,以滿足開發人員操作動畫的需求。

這個函數類似setTimeout,只調用一次。

function draw() {         requestAnimationFrame(draw);         // ... Code for Drawing the Frame ... }

 

遞迴調用,就可以實現定時器。

但是,這樣完全跟瀏覽器幀頻同步了,無法自訂動畫的幀頻,是無法滿足需求的。

 

接下來需要考慮如何控制幀頻。

簡單做法:

var fps = 30;function tick() {  setTimeout(function() {    requestAnimationFrame(draw);    draw(); // ... Code for Drawing the Frame ...  }, 1000 / fps);}tick();

 

這種做法,比較直觀的可以發現,每一次setTimeout執行的時候,都還要再等到下一個requestAnimationFrame事件到達,累積下去會造成動畫變慢。

 

自行控制時間跨度:

var fps = 30;var now;var then = Date.now();var interval = 1000/fps;var delta;function tick() {  requestAnimationFrame(draw);  now = Date.now();  delta = now - then;  if (delta > interval) {    // 這裡不能簡單then=now,否則還會出現上邊簡單做法的細微時間差問題。例如fps=10,每幀100ms,而現在每16ms(60fps)執行一次draw。16*7=112>100,需要7次才實際繪製一次。這個情況下,實際10幀需要112*10=1120ms>1000ms才繪製完成。    then = now - (delta % interval);    draw(); // ... Code for Drawing the Frame ...  }}tick();

 

 

針對低版本瀏覽器再最佳化:

如果瀏覽器沒有requestAnimationFrame函數,實際底層還只能用setTimeout類比,上邊做的都是無用功。那麼可以再改進一下。

var fps = 30;var now;var then = Date.now();var interval = 1000/fps;var delta;window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;function tick() {  if(window.requestAnimationFrame)   {      requestAnimationFrame(draw);      now = Date.now();      delta = now - then;      if (delta > interval) {        // 這裡不能簡單then=now,否則還會出現上邊簡單做法的細微時間差問題。例如fps=10,每幀100ms,而現在每16ms(60fps)執行一次draw。16*7=112>100,需要7次才實際繪製一次。這個情況下,實際10幀需要112*10=1120ms>1000ms才繪製完成。        then = now - (delta % interval);        draw(); // ... Code for Drawing the Frame ...      }   }   else   {       setTimeout(draw, interval);   }}tick();            

 


最後,還可以加上暫停。

var fps = 30;var pause = false;var now;var then = Date.now();var interval = 1000/fps;var delta;window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;function tick() {     if(pause)          return;   if(window.requestAnimationFrame)     {    ...     }     else     {          ...     }}tick();

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.