bevyengine / bevyengine/bevy

Precise input timing information

Open
#9,087 4 comments 8 reactions 0 assignees View on GitHub
A-Input C-Feature
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## What problem does this solve or what need does it fill?

The application I'm concerned with is rhythm games. Currently it is not possible to determine the time at which an input event (such as a keyboard press) occurred with precision better than 1 frame. However, rhythm games require input timing information which is more precise than this. For example, [the ECFA Fantastic window is 11ms](https://github.com/Simply-Love/Simply-Love-SM5/blob/818e08157f80e9ecacfccabb267cce085c263516/Scripts/SL_Init.lua#L206C34-L206C34) long, and [the osu! 300 window can be as short as 13.33ms](https://osu.ppy.sh/wiki/en/Client/Beatmap_editor/Song_setup#overall-difficulty). On the other hand, a frame at 144fps is 6.94 ms long, while a frame at 60fps is 16.66 ms long. This means that the error incurred by measuring the time of an input precise to the next frame could be 50% or more of the actual timing window, making it impossible for players to reliably input in the window.

Besides rhythm games, precise input timing information is also applicable to other issues, such as https://github.com/bevyengine/bevy/issues/5984 and https://github.com/bevyengine/bevy/issues/6183.

## What solution would you like?

Add `Instant::now()` to events processed in the winit event loop and the gilrs event loop. Additionally rewrite the gilrs integration so that gamepad events are polled continuously (like winit events) rather than once per frame so that these timestamps are accurate.

## What alternative(s) have you considered?

Use timing information from the OS passed through by winit and gilrs, instead of measuring it ourselves using `Instant::now()` in the event loop. This has several issues:
* OS timing information may be unreliable. For instance, some OS timing information is precise only to the millsecond, which might be suitable for rhythm games but not for other uses of timestamps. They might also be nonmonotonic etc.
* winit doesn't currently expose timing information from the OS (https://github.com/rust-windowing/winit/issues/1194)
* [gilrs timestamps are expressed as `SystemTime`](https://docs.rs/gilrs/latest/gilrs/ev/struct.Event.html#structfield.time), which could lead to issues. For instance these timestamps aren't monotonic and are affected by system time changes.

## Additional context

Contributor guide

Open the contributing guide

Research direction

Start by tracing the winit event loop and gilrs event loop integrations, focusing on where input events are processed and where gilrs is polled. The change is complete when both event sources provide monotonic Instant::now() timestamps and gilrs polling is continuous rather than once per frame, with timing accurate enough for rhythm-game input windows.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.