Trait bevy_state::state::SubStates

source ·
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.


/// 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, we want a GamePhase state to exist.
            /// We can set the initial value here or overwrite it through [`NextState`].
            Some(AppState::InGame { .. }) => Some(Self::Setup),
            /// If we don't want the `State<GamePhase>` resource to exist 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§

source

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§

source

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 from the returned Some as the initial state.

Value within Some is ignored if the state already exists in the world and only symbolises that the state should still exist.

Initial value can also be overwritten by NextState.

Provided Methods§

source

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§