我是 Rust 新手,但这是我解决相同问题的方法。
您可以通过调用回调来消除有问题的window.request_animation_frame
递归并同时实现 FPS 上限,该window.request_animation_frame
回调window.set_interval
检查 aRc<RefCell<bool>>
或其他内容以查看是否仍有动画帧请求未决。我不确定非活动标签行为在实践中是否会有所不同。
我将 bool 放入我的应用程序状态,因为无论如何我都在使用Rc<RefCell<...>>
to 来处理其他事件。我还没有检查以下是否按原样编译,但这是我如何执行此操作的相关部分:
pub struct MyGame {
...
should_request_render: bool, // Don't request another render until the previous runs, init to false since we'll fire the first one immediately.
}
...
let window = web_sys::window().expect("should have a window in this context");
let application_reference = Rc::new(RefCell::new(MyGame::new()));
let request_animation_frame = { // request_animation_frame is not forgotten! Its ownership is moved into the timer callback.
let application_reference = application_reference.clone();
let request_animation_frame_callback = Closure::wrap(Box::new(move || {
let mut application = application_reference.borrow_mut();
application.should_request_render = true;
application.handle_animation_frame(); // handle_animation_frame being your main loop.
}) as Box<FnMut()>);
let window = window.clone();
move || {
window
.request_animation_frame(
request_animation_frame_callback.as_ref().unchecked_ref(),
)
.unwrap();
}
};
request_animation_frame(); // fire the first request immediately
let timer_closure = Closure::wrap(
Box::new(move || { // move both request_animation_frame and application_reference here.
let mut application = application_reference.borrow_mut();
if application.should_request_render {
application.should_request_render = false;
request_animation_frame();
}
}) as Box<FnMut()>
);
window.set_interval_with_callback_and_timeout_and_arguments_0(
timer_closure.as_ref().unchecked_ref(),
25, // minimum ms per frame
)?;
timer_closure.forget(); // this leaks it, you could store it somewhere or whatever, depends if it's guaranteed to live as long as the page
您可以将结果set_interval
和timer_closure
in存储Option
在您的游戏状态中,以便您的游戏可以在出于某种原因需要时自行清理(也许?我还没有尝试过,它似乎会导致释放self
?)。除非损坏,否则循环引用不会自行擦除(然后您将Rc
s 有效地存储到应用程序内部的应用程序)。它还应该使您能够在运行时更改最大 fps,方法是停止间隔并使用相同的闭包创建另一个。