macroquad
macroquad copied to clipboard
Design discussion: high-precision touch/mouse input
I really like the miniquad's event-based input with impl EventHandler for Stage because it allows the input to be independent from FPS. For example: input from touch can come 100 times per second even if draw happens at 30 FPS on mobile.
In macroquad's examples currently the input is polled on each frame (example: is_key_down), which makes the input rate tied to the framerate. This would be a problem for apps that rely on high-frequency input, example: painting apps or Fruit Ninja-like games, because the lines a person draws with their finger will miss some input data that changes in between frames. On phone, the input rate reported from the screen is typically 100 FPS, while games run at 30-60 FPS.
I propose to have a way to handle events in macroquad independent of the framerate in a similar way it's done in miniquad.
What is your opinion?
My first thought: if you need low-level platform features - macroquad will not be the best fit. Macroquad goal is to provide raylib-like experience - with a simple main loop and raylib-like API.
So for low-level control I would suggest using pure miniquad + some helper libraries (like quad-gl )
Thanks for sharing your thoughts! I don't think of "high precision input" as low-level - it's still high-level platform feature since it abstracts input from the underlying platform. It just allows input to be "smooth" and not tied to framerate. Note that commercial games suffer from the same design issue they made early on (tying input to FPS.) It can also mean if a frame takes a long time to render (e.g. 0.5 seconds) the input will also lag. If input is separate from rendering loop, then it will feel "snappy" even if rendering is slow. Unity engine also has been struggling with this for a while. Some related articles:
Overwatch announcements for high precision input - Nov 2019
Unity forum threads throughout the years: 2012 and 2014
Unity partially fixed the issue for mobile Touch and Accelerometer input: https://docs.unity3d.com/Manual/MobileInput.html. However they didn't fix it for mouse (I think) because of legacy code.
In my Unity app I have custom code that gets "list of inputs since last frame" and it took me weeks to develop and get right, but the result is worth it (a painting app.)
I can use miniquad (and will), but will have to rewrite some of the high-level drawing functions of macroquad (ellipse, rectangle, I'm adding line too) because input precision is very important for me.
Anyway, quad-gl seems cool and I'll try it with miniquad to see how it feels! I've been looking for a rust drawing that cross-compiles for android and wasm for some time now, thanks for starting this project!
Found an implementation in SDL2 which is actually quite nice - you can keep the event loop {...} and have precision input: https://nukep.github.io/rust-sdl2/sdl2/event/struct.EventPump.html#method.poll_iter
Here's how the draw loop would loop like in this case:
let mut sdl_event_pump = sdl_context.event_pump().unwrap();
'running: loop {
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
for event in sdl_event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => break 'running,
Event::MouseButtonDown {
mouse_btn: MouseButton::Left,
x,
y,
..
} => {
println!("Left button down");
}
Event::MouseButtonUp {
mouse_btn: MouseButton::Left,
x,
y,
..
} => {
println!("Left button UP");
}
Event::MouseMotion { x, y, .. } => {
println!("Draw {} {}", x, y);
}
}
}
// draw frame here
next_frame.await()
}
that SDL even loop looks nice and I have nothing against it in macroquad!
I would say that if you like the macroquad's main loop design and overall direction to raylib-like library in rust - let's fix the high precision input in macroquad! I am more than welcome to adjust the library a bit!
However, if you don't like the macroquad's main loop - I don't think that macroquad's drawing code worse it. Macroquad's is quite tiny and going to be a tiny library - basically, it will provide a very specific main loop and a very specific way to work with context.
I like macroquad's main loop - it feels very simple and pleasant to work with! :) Also +1 for being tiny library, fast build times and small/fast to start is best. I'm testing some drawing on Android now .apk size is <400KB and startup time is < 10ms, awesome!
I'm also having issues with inputs being missed due to the state-based nature of the inputs not being accurate enough. We need some way to receive events, we really need an event processing system in the loop (winit does this really well for example, a loop { ... } doesn't).
EDIT: Optimally, there's no point in the async (especially the memory allocation thereof), a simple function callback, ala winit, makes a lot more sense as then you can handle events of inputs, window events to update things, render on the render event, etc....
winit does this really well for example, a loop { ... } doesn't
Can you tell us some more regarding your experience with winit events and event loop {...}? What are the pros and cons? Would be good to document here for future.
Is fast input now possible or is it still tied to frames?