bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.4k stars 3.59k forks source link

Add a `TimedCommand` helper #16442

Closed alice-i-cecile closed 5 days ago

alice-i-cecile commented 5 days ago

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

Performing a gameplay action after a specific amount of time has elapsed is a common and simple pattern.

Right now, this kind of sucks, because you need to make custom systems, components and tick timers for each effect (or build your own abstraction).

What solution would you like?

Add a TimedCommand helper in bevy_time.

struct TimedCommand { 
    timer: Timer, 
    command: Box<dyn Command> 
}

These would be stored as a Vec in a TimedCommands resource, and then all of the commands ticked (probably in First?) during a system.

Proposed by @cart on Discord.

What alternative(s) have you considered?

We could cannibalize bevy_animation's system for animation events, but that requires a weird dependency and isn't designed for this.

Additional context

This was prompted by my review of https://github.com/bevyengine/bevy/pull/16440 :)

Vrixyz commented 5 days ago

I feel like this would be adding specifics for something that could be modeled with a component containing a Timer + leveraging Trigger observer:

example API:

command.spawn(
  TimerWithEvent(
    Timer::new(Duration::from_secs(1),TimerMode::Once)
  )
).observe(|trigger: Trigger<TimerFinished>, mut commands: Commands| {
  // TODO: anything useful
  commands.entity(trigger.entity).despawn();
}
benfrankel commented 5 days ago

Also see this issue: https://github.com/bevyengine/bevy/issues/15129

alice-i-cecile commented 5 days ago

Using an observer is nice! It does mean that we can't tick all of the timers in a single system. Maybe that's okay?

alice-i-cecile commented 5 days ago

Closing as a duplicate of #15129; we should consolidate discussion there.