Path: blob/main/crates/bevy_state/src/state/resources.rs
6596 views
use core::ops::Deref;12use bevy_ecs::{3change_detection::DetectChangesMut,4resource::Resource,5system::ResMut,6world::{FromWorld, World},7};89use super::{freely_mutable_state::FreelyMutableState, states::States};1011#[cfg(feature = "bevy_reflect")]12use bevy_ecs::prelude::ReflectResource;1314#[cfg(feature = "bevy_reflect")]15use bevy_reflect::prelude::ReflectDefault;1617/// A finite-state machine whose transitions have associated schedules18/// ([`OnEnter(state)`](crate::state::OnEnter) and [`OnExit(state)`](crate::state::OnExit)).19///20/// The current state value can be accessed through this resource. To *change* the state,21/// queue a transition in the [`NextState<S>`] resource, and it will be applied during the22/// [`StateTransition`](crate::state::StateTransition) schedule - which by default runs after `PreUpdate`.23///24/// You can also manually trigger the [`StateTransition`](crate::state::StateTransition) schedule to apply the changes25/// at an arbitrary time.26///27/// The starting state is defined via the [`Default`] implementation for `S`.28///29/// ```30/// use bevy_state::prelude::*;31/// use bevy_ecs::prelude::*;32/// use bevy_state_macros::States;33///34/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]35/// enum GameState {36/// #[default]37/// MainMenu,38/// SettingsMenu,39/// InGame,40/// }41///42/// fn game_logic(game_state: Res<State<GameState>>) {43/// match game_state.get() {44/// GameState::InGame => {45/// // Run game logic here...46/// },47/// _ => {},48/// }49/// }50/// ```51#[derive(Resource, Debug)]52#[cfg_attr(53feature = "bevy_reflect",54derive(bevy_reflect::Reflect),55reflect(Resource, Debug, PartialEq)56)]57pub struct State<S: States>(pub(crate) S);5859impl<S: States> State<S> {60/// Creates a new state with a specific value.61///62/// To change the state use [`NextState<S>`] rather than using this to modify the `State<S>`.63pub fn new(state: S) -> Self {64Self(state)65}6667/// Get the current state.68pub fn get(&self) -> &S {69&self.070}71}7273impl<S: States + FromWorld> FromWorld for State<S> {74fn from_world(world: &mut World) -> Self {75Self(S::from_world(world))76}77}7879impl<S: States> PartialEq<S> for State<S> {80fn eq(&self, other: &S) -> bool {81self.get() == other82}83}8485impl<S: States> Deref for State<S> {86type Target = S;8788fn deref(&self) -> &Self::Target {89self.get()90}91}9293/// The next state of [`State<S>`].94///95/// This can be fetched as a resource and used to queue state transitions.96/// To queue a transition, call [`NextState::set`] or mutate the value to [`NextState::Pending`] directly.97///98/// Note that these transitions can be overridden by other systems:99/// only the actual value of this resource during the [`StateTransition`](crate::state::StateTransition) schedule matters.100///101/// ```102/// use bevy_state::prelude::*;103/// use bevy_ecs::prelude::*;104///105/// #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]106/// enum GameState {107/// #[default]108/// MainMenu,109/// SettingsMenu,110/// InGame,111/// }112///113/// fn start_game(mut next_game_state: ResMut<NextState<GameState>>) {114/// next_game_state.set(GameState::InGame);115/// }116/// ```117#[derive(Resource, Debug, Default, Clone)]118#[cfg_attr(119feature = "bevy_reflect",120derive(bevy_reflect::Reflect),121reflect(Resource, Default, Debug)122)]123pub enum NextState<S: FreelyMutableState> {124/// No state transition is pending125#[default]126Unchanged,127/// There is a pending transition for state `S`128Pending(S),129}130131impl<S: FreelyMutableState> NextState<S> {132/// Tentatively set a pending state transition to `Some(state)`.133pub fn set(&mut self, state: S) {134*self = Self::Pending(state);135}136137/// Remove any pending changes to [`State<S>`]138pub fn reset(&mut self) {139*self = Self::Unchanged;140}141}142143pub(crate) fn take_next_state<S: FreelyMutableState>(144next_state: Option<ResMut<NextState<S>>>,145) -> Option<S> {146let mut next_state = next_state?;147148match core::mem::take(next_state.bypass_change_detection()) {149NextState::Pending(x) => {150next_state.set_changed();151Some(x)152}153NextState::Unchanged => None,154}155}156157158