Path: blob/main/crates/bevy_state/src/state/sub_states.rs
6596 views
use bevy_ecs::schedule::Schedule;12use super::{freely_mutable_state::FreelyMutableState, state_set::StateSet, states::States};3pub use bevy_state_macros::SubStates;45/// A sub-state is a state that exists only when the source state meet certain conditions,6/// but unlike [`ComputedStates`](crate::state::ComputedStates) - while they exist they can be manually modified.7///8/// The default approach to creating [`SubStates`] is using the derive macro, and defining a single source state9/// and value to determine its existence.10///11/// ```12/// # use bevy_ecs::prelude::*;13/// # use bevy_state::prelude::*;14///15/// #[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]16/// enum AppState {17/// #[default]18/// Menu,19/// InGame20/// }21///22///23/// #[derive(SubStates, Clone, PartialEq, Eq, Hash, Debug, Default)]24/// #[source(AppState = AppState::InGame)]25/// enum GamePhase {26/// #[default]27/// Setup,28/// Battle,29/// Conclusion30/// }31/// ```32///33/// you can then add it to an App, and from there you use the state as normal:34///35/// ```36/// # use bevy_ecs::prelude::*;37/// # use bevy_state::prelude::*;38///39/// # struct App;40/// # impl App {41/// # fn new() -> Self { App }42/// # fn init_state<S>(&mut self) -> &mut Self {self}43/// # fn add_sub_state<S>(&mut self) -> &mut Self {self}44/// # }45/// # struct AppState;46/// # struct GamePhase;47///48/// App::new()49/// .init_state::<AppState>()50/// .add_sub_state::<GamePhase>();51/// ```52///53/// In more complex situations, the recommendation is to use an intermediary computed state, like so:54///55/// ```56/// # use bevy_ecs::prelude::*;57/// # use bevy_state::prelude::*;58///59/// /// Computed States require some state to derive from60/// #[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]61/// enum AppState {62/// #[default]63/// Menu,64/// InGame { paused: bool }65/// }66///67/// #[derive(Clone, PartialEq, Eq, Hash, Debug)]68/// struct InGame;69///70/// impl ComputedStates for InGame {71/// /// We set the source state to be the state, or set of states,72/// /// we want to depend on. Any of the states can be wrapped in an Option.73/// type SourceStates = Option<AppState>;74///75/// /// We then define the compute function, which takes in the AppState76/// fn compute(sources: Option<AppState>) -> Option<Self> {77/// match sources {78/// /// When we are in game, we want to return the InGame state79/// Some(AppState::InGame { .. }) => Some(InGame),80/// /// Otherwise, we don't want the `State<InGame>` resource to exist,81/// /// so we return None.82/// _ => None83/// }84/// }85/// }86///87/// #[derive(SubStates, Clone, PartialEq, Eq, Hash, Debug, Default)]88/// #[source(InGame = InGame)]89/// enum GamePhase {90/// #[default]91/// Setup,92/// Battle,93/// Conclusion94/// }95/// ```96///97/// However, you can also manually implement them. If you do so, you'll also need to manually implement the `States` & `FreelyMutableState` traits.98///99/// ```100/// # use bevy_ecs::prelude::*;101/// # use bevy_state::prelude::*;102/// # use bevy_state::state::{FreelyMutableState, NextState};103///104/// /// Computed States require some state to derive from105/// #[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]106/// enum AppState {107/// #[default]108/// Menu,109/// InGame { paused: bool }110/// }111///112/// #[derive(Clone, PartialEq, Eq, Hash, Debug)]113/// enum GamePhase {114/// Setup,115/// Battle,116/// Conclusion117/// }118///119/// impl SubStates for GamePhase {120/// /// We set the source state to be the state, or set of states,121/// /// we want to depend on. Any of the states can be wrapped in an Option.122/// type SourceStates = Option<AppState>;123///124/// /// We then define the compute function, which takes in the [`Self::SourceStates`]125/// fn should_exist(sources: Option<AppState>) -> Option<Self> {126/// match sources {127/// /// When we are in game, we want a GamePhase state to exist.128/// /// We can set the initial value here or overwrite it through [`NextState`].129/// Some(AppState::InGame { .. }) => Some(Self::Setup),130/// /// If we don't want the `State<GamePhase>` resource to exist we return [`None`].131/// _ => None132/// }133/// }134/// }135///136/// impl States for GamePhase {137/// const DEPENDENCY_DEPTH : usize = <GamePhase as SubStates>::SourceStates::SET_DEPENDENCY_DEPTH + 1;138/// }139///140/// impl FreelyMutableState for GamePhase {}141/// ```142#[diagnostic::on_unimplemented(143message = "`{Self}` can not be used as a sub-state",144label = "invalid sub-state",145note = "consider annotating `{Self}` with `#[derive(SubStates)]`"146)]147pub trait SubStates: States + FreelyMutableState {148/// The set of states from which the [`Self`] is derived.149///150/// This can either be a single type that implements [`States`], or a tuple151/// containing multiple types that implement [`States`], or any combination of152/// types implementing [`States`] and Options of types implementing [`States`].153type SourceStates: StateSet;154155/// This function gets called whenever one of the [`SourceStates`](Self::SourceStates) changes.156/// The result is used to determine the existence of [`State<Self>`](crate::state::State).157///158/// If the result is [`None`], the [`State<Self>`](crate::state::State) resource will be removed from the world,159/// otherwise if the [`State<Self>`](crate::state::State) resource doesn't exist160/// it will be created from the returned [`Some`] as the initial state.161///162/// Value within [`Some`] is ignored if the state already exists in the world163/// and only symbolizes that the state should still exist.164///165/// Initial value can also be overwritten by [`NextState`](crate::state::NextState).166fn should_exist(sources: Self::SourceStates) -> Option<Self>;167168/// This function sets up systems that compute the state whenever one of the [`SourceStates`](Self::SourceStates)169/// change. It is called by `App::add_computed_state`, but can be called manually if `App` is not170/// used.171fn register_sub_state_systems(schedule: &mut Schedule) {172Self::SourceStates::register_sub_state_systems_in_schedule::<Self>(schedule);173}174}175176177