Type-safe `Instant` equivalent for `bevy_time` that encodes source of clock
- 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?
`bevy_time` doesn't have any ergonomic equivalent to ``std::time::Instant`` that would work with built-in timekeeping(``Res>``)
The closest equivalent is to use ``Stopwatch``, but it requires to be manually ticked every schedule update, which is fine in one type of situations, but can be problematic/non-trivial/expensive in other kinds of situations.
Also as minor downside, ``Stopwatch`` is not type-safe and will gladly accept tick delta from wrong Time.
## What solution would you like?
Add `Instant`-like type(or newtype) based on Duration(with ability to get underlying Duration) with equivalent to `bevy_time::Time` generic argument, e.g. ``TimeInstant``(maybe chose better name)
Add ``bevy_time::Time::now(&self) -> TimeInstant``
Also add ``TimeInstant::as_generic(&self) -> TimeInstant<()>`` to ``TimeInstant`` for cases when it needs to be type-erased.
So, final API looks like that
```rs
#[Derive(Component)]
struct Spell {
last_used: TimeInstant,
cooldown: Duration,
damage: f32,
kind: SpellKind,
}
fn on_cast_spell(spell: On, spells: Query<&mut Ability>, transform: Query<&Transform>, mut commands: Commands, time_res: Res>) {
let mut spell_info = spells.get_mut(spell.spell).unwrap();
if time_res.now() - spell_info.last_used < spell_info.cooldown { return; }
// Or
if spell_info.last_used.elapsed(time_res) < spell_info.cooldown { return; }
spell_info.last_used = time_res::now();
let player_pos = transform.get(spell.caster).unwrap();
commands.trigger(SpawnProjectile { damage: spell_info.damage, position: player_pos.translation. kind: spell_info.kind, owner: spell.caster });
}
```
Additionally that would be immediately useful for refactoring [``crates/bevy_camera_controller/src/pan_orbit_camera/controller/smoothing.rs``](https://github.com/bevyengine/bevy/blob/main/crates/bevy_camera_controller/src/pan_orbit_camera/controller/smoothing.rs) to replace all usages of ``std::time::Instant`` in favor of ``Time``.
Also probably it would be good to add ``Timer`` equivalent based around ``TimeInstant``
```rs
let mut timer = TimerInstant::new(start, duration);
timer.update(time_now);
trace!("{}", timer.fraction());
trace!("{}", timer.is_finished());
```
Contributor guide
Research direction
Start by reading the existing bevy_time APIs, especially Time and Stopwatch, then inspect crates/bevy_camera_controller/src/pan_orbit_camera/controller/smoothing.rs to understand the std::time::Instant usage. Done means an agreed type-safe Instant-like API for clock sources, with the requested timekeeping use cases addressed and the smoothing code refactored if included in scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100