IyesGames / iyes_loopless

Alternatives to Bevy States, FixedTimestep, Run Criteria, that do not use "stage looping" and are composable
Other
249 stars 27 forks source link

Is there alternative to bevy's state stack? #19

Closed konceptosociala closed 2 years ago

konceptosociala commented 2 years ago

I've switched from bevy state system into loopless, because there wasn't any information about "setup" systems in it, only loop, but I've found such implementation there. But after I found out such realization in bevy cheatbook (which I've not remarked somehow), I've also seen such thing as "stacks" which lets you make implementation of "pause" state etc. Does similar thing exists in loopless, or I need to get back to bevy systems?

P.S.: Or is there another way to implement pause menu or smth like this? Thx

mszegedy commented 2 years ago

Wow, I wanted to open an issue about this just about three days ago. Same brain cell. Note that you can always use Bevy states, and use loopless only for the run conditions, but yeah, it still has some of the disadvantages the Cheatbook mentions.

inodentry commented 2 years ago

A state stack is deliberately not implemented ... because loopless (and future bevy stageless) lets you do something better: just use multiple orthogonal state types!

/// App State: which "screen" are we in
enum AppScreen {
    Splash,
    Loading,
    MainMenu,
    Settings,
    Cutscene,
    InGame,
    // ...
}

/// App State: How is the game running, if in-game?
enum GameControlState {
    Normal,
    Paused,
    /// for a simulation game?
    FastForward,
}

/// App State: what game mode has the player selected?
enum GameMode {
    Singleplayer,
    Multiplayer,
    Tutorial,
    // ...
}

You can create as many state types as you want! You can trigger transitions on each of them independently, and make your systems conditional on multiple states at once! Therefore you can use different combinations of them to control whatever functionality should be affected.

// "input controls": only in-game, when not paused
app.add_system(
    input_controls
        .run_in_state(AppScreen::InGame)
        .run_not_in_state(GameControlState::Paused)
);
// "game ai system": only in singleplayer mode when not paused
app.add_system(
    game_ai
        .run_in_state(AppScreen::InGame)
        .run_not_in_state(GameControlState::Paused)
        .run_in_state(GameMode::Singleplayer)
);

To pause/unpause the game, just perform state transitions on the GameControlState while remaining in the AppScreen::InGame state.

Having multiple state types like this (with each system being affected by whatever combination is relevant to it) is so much more flexible than the "state stack" paradigm offered by the legacy Bevy/Amethyst states.

Enjoy!