Trait bevy::state::prelude::SubStates

pub trait SubStates: States + FreelyMutableState {
    type SourceStates: StateSet;

    // Required method
    fn should_exist(sources: Self::SourceStates) -> Option<Self>;

    // Provided method
    fn register_sub_state_systems(schedule: &mut Schedule) { ... }
}
Expand description

A sub-state is a state that exists only when the source state meet certain conditions, but unlike ComputedStates - while they exist they can be manually modified.

The default approach to creating SubStates is using the derive macro, and defining a single source state and value to determine it’s existence.


#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]
enum AppState {
    #[default]
    Menu,
    InGame
}


#[derive(SubStates, Clone, PartialEq, Eq, Hash, Debug, Default)]
#[source(AppState = AppState::InGame)]
enum GamePhase {
    #[default]
    Setup,
    Battle,
    Conclusion
}

you can then add it to an App, and from there you use the state as normal:



    App::new()
        .init_state::<AppState>()
        .add_sub_state::<GamePhase>();

In more complex situations, the recommendation is to use an intermediary computed state, like so:


/// Computed States require some state to derive from
#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]
enum AppState {
    #[default]
    Menu,
    InGame { paused: bool }
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
struct InGame;

impl ComputedStates for InGame {
    /// We set the source state to be the state, or set of states,
    /// we want to depend on. Any of the states can be wrapped in an Option.
    type SourceStates = Option<AppState>;

    /// We then define the compute function, which takes in the AppState
    fn compute(sources: Option<AppState>) -> Option<Self> {
        match sources {
            /// When we are in game, we want to return the InGame state
            Some(AppState::InGame { .. }) => Some(InGame),
            /// Otherwise, we don't want the `State<InGame>` resource to exist,
            /// so we return None.
            _ => None
        }
    }
}

#[derive(SubStates, Clone, PartialEq, Eq, Hash, Debug, Default)]
#[source(InGame = InGame)]
enum GamePhase {
    #[default]
    Setup,
    Battle,
    Conclusion
}

However, you can also manually implement them. If you do so, you’ll also need to manually implement the States & FreelyMutableState traits. Unlike the derive, this does not require an implementation of Default, since you are providing the exists function directly.


/// Computed States require some state to derive from
#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]
enum AppState {
    #[default]
    Menu,
    InGame { paused: bool }
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
enum GamePhase {
    Setup,
    Battle,
    Conclusion
}

impl SubStates for GamePhase {
    /// We set the source state to be the state, or set of states,
    /// we want to depend on. Any of the states can be wrapped in an Option.
    type SourceStates = Option<AppState>;

    /// We then define the compute function, which takes in the [`Self::SourceStates`]
    fn should_exist(sources: Option<AppState>) -> Option<Self> {
        match sources {
            /// When we are in game, so we want a GamePhase state to exist, and the default is
            /// GamePhase::Setup
            Some(AppState::InGame { .. }) => Some(GamePhase::Setup),
            /// Otherwise, we don't want the `State<GamePhase>` resource to exist,
            /// so we return None.
            _ => None
        }
    }
}

impl States for GamePhase {
    const DEPENDENCY_DEPTH : usize = <GamePhase as SubStates>::SourceStates::SET_DEPENDENCY_DEPTH + 1;
}

impl FreelyMutableState for GamePhase {}

Required Associated Types§

type SourceStates: StateSet

The set of states from which the Self is derived.

This can either be a single type that implements States, or a tuple containing multiple types that implement States, or any combination of types implementing States and Options of types implementing States

Required Methods§

fn should_exist(sources: Self::SourceStates) -> Option<Self>

This function gets called whenever one of the SourceStates changes. The result is used to determine the existence of State<Self>.

If the result is None, the State<Self> resource will be removed from the world, otherwise if the State<Self> resource doesn’t exist - it will be created with the Some value.

Provided Methods§

fn register_sub_state_systems(schedule: &mut Schedule)

This function sets up systems that compute the state whenever one of the SourceStates change. It is called by App::add_computed_state, but can be called manually if App is not used.

Object Safety§

This trait is not object safe.

Implementors§