Skip to content

Commit

Permalink
Add set_state extension method to Commands (#15083)
Browse files Browse the repository at this point in the history
# Objective

- Improve the ergonomics of managing states.

## Solution

- Add `set_state` extension method to `Commands` so you don't need to
type out `ResMut<NextState<S>>` to update a state. It also reduces
system parameter list size when you already have `Commands`.
- I only updated a couple examples to showcase how it can be used. There
*is* a potential perf cost to introducing `Commands` so this method
shouldn't necessarily be used everywhere.

## Testing

- Tested the updated examples: `game_menu` and `alien_cake_addict`.

---

## Showcase

Add `Commands::set_state` method for easily updating states.

Set directly:
```rust
fn go_to_game(mut game_state: ResMut<NextState<GameState>>) {
    game_state.set(GameState::Play);
}
```

Set with commands (**NEW**):
```rust
fn go_to_game(mut commands: Commands) {
    commands.set_state(GameState::Play);
}
```
  • Loading branch information
UkoeHB authored Sep 9, 2024
1 parent 82e416d commit ce32b5c
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
30 changes: 30 additions & 0 deletions crates/bevy_state/src/commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use bevy_ecs::{system::Commands, world::World};
use bevy_utils::tracing::debug;

use crate::state::{FreelyMutableState, NextState};

/// Extension trait for [`Commands`] adding `bevy_state` helpers.
pub trait CommandsStatesExt {
/// Sets the next state the app should move to.
///
/// Internally this schedules a command that updates the [`NextState<S>`](crate::prelude::NextState)
/// resource with `state`.
///
/// Note that commands introduce sync points to the ECS schedule, so modifying `NextState`
/// directly may be more efficient depending on your use-case.
fn set_state<S: FreelyMutableState>(&mut self, state: S);
}

impl CommandsStatesExt for Commands<'_, '_> {
fn set_state<S: FreelyMutableState>(&mut self, state: S) {
self.add(move |w: &mut World| {
let mut next = w.resource_mut::<NextState<S>>();
if let NextState::Pending(prev) = &*next {
if *prev != state {
debug!("overwriting next state {:?} with {:?}", prev, state);
}
}
next.set(state);
});
}
}
4 changes: 4 additions & 0 deletions crates/bevy_state/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#[cfg(feature = "bevy_app")]
/// Provides [`App`](bevy_app::App) and [`SubApp`](bevy_app::SubApp) with state installation methods
pub mod app;
/// Provides extension methods for [`Commands`](bevy_ecs::prelude::Commands).
pub mod commands;
/// Provides definitions for the runtime conditions that interact with the state system
pub mod condition;
/// Provides definitions for the basic traits required by the state system
Expand All @@ -55,6 +57,8 @@ pub mod prelude {
#[doc(hidden)]
pub use crate::app::AppExtStates;
#[doc(hidden)]
pub use crate::commands::CommandsStatesExt;
#[doc(hidden)]
pub use crate::condition::*;
#[cfg(feature = "bevy_reflect")]
#[doc(hidden)]
Expand Down

0 comments on commit ce32b5c

Please sign in to comment.