2013-09-25 22 views
9

tôi bắt đầu vòng lặpJavascript - Không thể điều chỉnh FrameRate - requestanimationframe

function gameLoop(){ 
    update(); 
    draw(); 
    requestAnimFrame(gameLoop); 
} 

var requestAnimFrame = window.requestAnimationFrame || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame || 
        window.oRequestAnimationFrame || 
        window.msRequestAnimationFrame || 
        function(callback) { 
         window.setTimeout(callback, 1000/1); 
        }; 
  1. tôi không thể điều chỉnh tỷ lệ khung hình. Nó luôn luôn rất nhanh. Tại sao tôi không thể thay đổi nó thành 1 khung hình một giây. Tôi muốn làm điều này chỉ cho mục đích thử nghiệm.
  2. Tôi có phải xóa canvas mỗi lần không? Dường như nó hoạt động tốt mà không làm sạch nó.

Cảm ơn.

Đây là một liên kết đến một fiddle cho mã hoàn chỉnh: complete code

Cảm ơn

Trả lời

9

RAF bị khóa đến của giám sát đồng bộ, thường 60 Hz, vì vậy chúng tôi không thể điều chỉnh FPS cho nó trong bản thân (trình duyệt có thể giảm FPS khi tab không hoạt động hoặc trên pin).

Ngoài ra, những gì bạn đang cố gắng thay đổi là dự phòng cho việc điền nhiều lần; đó là: nếu rAF không được hỗ trợ trong trình duyệt, thay vào đó nó sẽ sử dụng setTimeout. Tuy nhiên, hầu hết các trình duyệt hiện nay làm hỗ trợ rAF (thậm chí không được đặt trước) để setTimeout sẽ không bao giờ được sử dụng.

Bạn có thể làm hai việc:

  • Thay RAF trong vòng lặp của bạn bằng cách sử dụng setTimeout trực tiếp (khi kiểm tra)

Ví dụ:

var FPS = 1; 

function testLoop() { 

    ... ordinary code 

    setTimeout(testLoop, 1000/FPS); 
} 
  • Throttle Raf bằng cách sử dụng bộ đếm:

Ví dụ:

var framesToSkip = 60, 
    counter = 0; 

function loop() { 

    if (counter < framesToSkip) { 
     counter++; 
     requestAnimationFrame(loop); 
     return; 
    } 

    /// do regular stuff 

    counter = 0; 
    requestAnimationFrame(loop); 
} 

MODIFIED FIDDLE HERE

Có rất có thể những cách tốt hơn để thực hiện điều tiết, nhưng tôi đang cố gắng để chỉ hiển thị các nguyên tắc cơ bản. Điều này sẽ vẫn chạy ở tốc độ tối đa, 60 FPS, nhưng mã của bạn sẽ làm tối thiểu các hoạt động và chỉ khi bộ đếm đã đạt đến số lượng của nó, nó sẽ thực thi mã chính.

Bạn không cần phải xóa canvas mỗi lần nếu nội dung bạn vẽ tiếp theo sẽ bao gồm nội dung được vẽ trước đó hoặc nếu bạn muốn giữ nội dung đó. Bạn cũng có thể xóa một phần để tối ưu hóa thêm, nếu cần.

0

requestAnimationFrame sẽ chạy với tốc độ khung hình tối đa có thể đạt được (tối đa 60 khung hình/giây). Điều này là bởi vì nó sẽ luôn cung cấp cho bạn khung hình hoạt hình tiếp theo.

Thông số bạn đã điều chỉnh chỉ dành cho polyfill, sẽ được kích hoạt nếu trình duyệt của bạn không triển khai requestAnimationFrame.

Nếu bạn muốn thử sơn một giây cho mục đích thử nghiệm, hãy thử setInterval để thay thế.

0

Đó là cách hoạt động của requestAnimationFrame. Nếu bạn muốn có tốc độ khung hình cụ thể, chỉ sử dụng setTimeout.

Thông thường bạn sẽ có tham số, là thời gian hiện tại. So sánh nó với thời gian của khung hình cuối cùng để tìm hiểu khoảng cách dọc theo hình động sẽ di chuyển.

1

Cách trình duyệt và javascript hoạt động gây khó khăn cho việc thiết lập tốc độ khung hình cố định. Giả sử bạn muốn làm điều gì đó sau mỗi giây, như cập nhật và vẽ. Một cách để thực hiện điều đó có thể là gọi window.setTimeout() với cài đặt một giây. Nhưng vấn đề là điều này không phải là đáng tin cậy, ngay cả khi bạn cấu hình một cuộc gọi lại mỗi giây bạn không thể chắc chắn tất cả các cuộc gọi lại sẽ đúng giờ. Ví dụ, một bộ xử lý cao có thể làm cho các cuộc gọi lại đến muộn hơn nhiều so với mức cần thiết. Và ngay cả khi các cuộc gọi lại sẽ đúng giờ, bạn không thể kiểm soát được thời điểm bản vẽ thực tế cho màn hình sẽ diễn ra. Một cách tốt hơn để xử lý nó là chấp nhận thực tế là bạn không thể nhận được thời gian cuộc gọi chính xác, và thay vào đó, bất cứ khi nào bạn nhận được cuộc gọi, bạn sẽ tính toán thời gian đã trôi qua và hành động theo đó . Điều này có nghĩa là bạn sẽ cho phép hệ thống quyết định tốc độ khung hình và bạn chỉ chăm sóc cập nhật hoạt ảnh hoặc trò chơi của mình tùy thuộc vào thời gian đã trôi qua.

requestAnimationFrame là một chức năng mới hơn được hỗ trợ bởi hầu hết các trình duyệt lúc này đặc biệt hữu ích cho trò chơi. Nó sẽ được gọi mỗi lần trình duyệt sẵn sàng để vẽ, điều đó rất tốt. Sau đó, bạn sẽ biết rằng các bản cập nhật và bản vẽ bạn đang thực hiện sẽ diễn ra ngay trước khi khung thực tế được vẽ ra màn hình.

Dưới đây là ví dụ về cách bạn có thể cập nhật trò chơi của mình để tính chênh lệch thời gian.

var lastTimestamp = +new Date; 

function gameLoop(timestamp) { 
    var now = +new Date; 
    var dt = now - lastTimestamp; 

    // dt is the amount of time in ms that has passed since last call. 
    // update takes this time difference (in seconds) and can then perform its 
    // updates based on time passed. 
    update(dt/1000); 
    draw(); 
    lastTimestamp = now; 
    requestAnimationFrame(gameLoop); 
} 
6

Một chút muộn cho bữa tiệc, nhưng đây là cách để có được lợi ích của RAF trong khi cũng kiểm soát khung hình/giây.

Lưu ý: requestAnimationFrame giờ đây có cách làm tốt hơn bằng cách sử dụng mẫu mã trong câu trả lời gốc cũ 3 năm của tôi ... xem cập nhật của tôi bên dưới để biết cách mới và cải tiến.

[Cập nhật: requestAnimationFrame bây giờ có một cách tốt hơn để điều tiết]

Phiên bản mới của requestAnimationFrame bây giờ tự động chuyển timestamp hiện tại mà bạn có thể sử dụng để tăng tốc thực thi mã của bạn.

Dưới đây là ví dụ mã để thực thi mã của bạn mỗi 1000ms:

var nextTime=0; 
var delay=1000; 

function gameLoop(currentTime){ 
    if(currentTime<nextTime){requestAnimationFrame(gameLoop); return;} 
    nextTime=currentTime+delay; 
    // do stuff every 1000ms 
    requestAnimationFrame(looper); 
} 

}

+0

Âm thanh rất hợp lý và thông minh. – nerkn

+0

bạn không nên hoán đổi setTimeout và requestAnimationFrame bằng cách nào đó? Trong ví dụ của bạn, cập nhật và vẽ được gọi tại sự kiện setTimeout, vẫn không đồng bộ trong khi phần gameloop() được đồng bộ hóa (nhưng không có gì ngoài việc đặt thời gian chờ) –

+0

@DanielAlder. Mã này là một vài năm tuổi và bây giờ 'requestAnimationFrame' tự động gửi trong một dấu thời gian để' setTimeout' không còn cần thiết nữa. Sử dụng dấu thời gian để điều chỉnh hoạt ảnh. – markE

2

Bạn nên xem xét điều này bài viết đưa ra cách xử lý thích hợp đối tượng. http://creativejs.com/resources/requestanimationframe/

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

Đây là mã tôi nghĩ rằng bạn muốn, nhưng trong bài viết gốc nó nói sử dụng requestAnimationFrame, nhưng ở đây tôi đang sử dụng requestAnimFrame. Tôi nghĩ có thể nó đã thay đổi và bạn phải sử dụng requestAnimFrame ngay bây giờ.requestAnimationFrame không hoạt động cho tôi trong khi requestAnimFrame đã làm.

Các vấn đề liên quan