Reputation: 77
I'm trying to build an NES emulator using winit
, which entails building a game loop which should run exactly 60 times per second.
At first, I used std::thread
to create a separate thread where the game loop would run and wait 16 milliseconds before running again. This worked quite well, until I tried to compile the program again targeting WebAssembly. I then found out that both winit::window::Window
and winit::event_loop::EventLoopProxy
are not Send
when targeting Wasm, and that std::thread::spawn
panics in Wasm.
After some struggle, I decided to try to do the same thing using task::spawn_local
from one of the main asynchronous runtimes. Ultimately, I went with async_std
.
I'm not used to asynchronous programming, so I'm not even sure if what I'm trying to do could work.
My idea is to do something like this:
use winit::{window::WindowBuilder, event_loop::EventLoop};
use std::time::Duration;
fn main() {
let event_loop = EventLoop::new();
let _window = WindowBuilder::new()
.build(&event_loop);
async_std::task::spawn_local(async {
// game loop goes here
loop {
// [update game state]
// [update frame buffer]
// [send render event with EventLoopProxy]
async_std::task::sleep(Duration::from_millis(16)).await;
// ^ note: I'll be using a different sleep function with Wasm
}
});
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
match event {
// ...
_ => ()
}
});
}
The problem with this approach is that the game loop will never run. If I'm not mistaken, some asynchronous code in the main thread would need to be blocked (by calling .await
) for the runtime to poll other Future
s, such as the one spawned by the spawn_local
function. I can't do this easily, since event_loop.run
is not asynchronous.
Having time to await
other events shouldn't be a problem, since the control flow is set to wait.
Testing this on native code, nothing inside the game loop ever runs. Testing this on Wasm code (with wasm_timer::Delay
as the sleep function), the game loop does run, but at a very low framerate and with long intervals of halting.
Having explained my situation, I would like to ask: is it possible to do what I'm trying to do, and if it is, how would I approach it? I will also accept answers telling me how I could try to do this differently, such as by using web workers.
Thanks in advance!
Upvotes: 3
Views: 999