Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement pausing #206

Open
benfrankel opened this issue Jul 30, 2024 · 10 comments
Open

Implement pausing #206

benfrankel opened this issue Jul 30, 2024 · 10 comments
Labels
enhancement New feature or request
Milestone

Comments

@benfrankel
Copy link
Collaborator

benfrankel commented Jul 30, 2024

How this can be implemented:

  • Define a state struct Pause(bool) somewhere (core/pause.rs if we had core/, otherwise probably just src/pause.rs or I guess src/lib.rs).
  • Every system that ought to not run while the game is paused should add .run_if(not(in_state(Paused(true)))) on a case-by-case basis (this could be made more ergonomic with a custom run condition or system set provided in pause.rs).
  • For a pause menu, we'd need a separate state, probably a sub-state of Screen::Playing, and toggle Pause when you enter / exit that state. In my jam game I had an enum PlayingMenu { Pause, LevelUp, ... }.
@benfrankel benfrankel added this to the Bevy Jam 6 milestone Jul 30, 2024
@benfrankel benfrankel added the enhancement New feature or request label Jul 30, 2024
@janhohenheim
Copy link
Member

image

We should probably replace the default behavior of Esc by pause while we are on it.

@TheKnarf
Copy link

TheKnarf commented Aug 1, 2024

Recently used this template for a game jam, and this was the one thing I felt was missing / was wrong from the template.

Screenshot 2024-08-01 at 10 25 53

I think the screen state should probably be a stack! If you want to pause the game you should push a pause state on top of the stack. If you then want to navigate to a settings menu you can push that as well on top of the stack. Then by leaving the settings menu you just pop it from the stack, and then to leave the pause state you pop it from the stack.

That way you can re-use a settings menu from both the start screen and from a main menu (without having any special logic in the settings menu).

  • Going from one state to another: pop the stack and push the next state
  • Going to a sub-menu / sub-state: push the state on top of the stack

The Esc-button should always pop the top of the stack if there is more than one item on the stack.
And have a special case for if there is only one state on the stack and that state is the Playing state, then it'll push a Pause state on top.

Game logic needs a .run_if(game_state_stack.top_of_stack() == Playing) and game components needs a ScopedStateEitherOnTopOrBottomOfStack(Playing). You don't want to de-spawn the game in the pause menu, but you do want to de-spawn pause-menu-components if you push a settings-menu on top of the stack, so the scoped check should always check if the state exists either at the top or bottom of the stack.
And then you'll also need a generic event type for top-most element of the stack changing, so that you can observe it and push new state when you enter or leave a menu/sub-menu.

Screenshot 2024-08-01 at 10 30 11

Additionally it would be practical if the template implemented a "Backdrop" component (something that fills the entire screen, is black and transparent) that can render over the game but under any menus. This would also mean that you should probably have a z-index.rs file that specify z-indexes for for gameplay-elements, backdrop, and menus.

This pattern will also capture the use-case that is if you are making a single player game and want the game to pause while you are in an inventory screen (or map screen, or upgrade screen, or shop screen, etc). And can support arbitrarily deep menus without any special code.

@benfrankel
Copy link
Collaborator Author

benfrankel commented Aug 1, 2024

bevy_state doesn't currently support state stacks, so that approach probably won't be practical for this template. I agree that it's useful though, and it's supported in pyri_state, so maybe one day bevy_state will support it as well :)

@TheKnarf
Copy link

TheKnarf commented Aug 1, 2024

Would it work to create your own type using a resource that tracks the stack. And two states that track the top and bottom of the stack with a system that syncs the two states with the state of the stack?

Either that or just not use bevy_state, but implement your own type/system for stacks. Really isn't a point in using bevy_state if its not the right tool for the job.

@benfrankel
Copy link
Collaborator Author

benfrankel commented Aug 1, 2024

Yeah, in my own project I would agree. The (not-yet-fully-codified) design principles of this template include 1. not using any 3rd-party dependencies besides bevy, and 2. not introducing complexity that a relative beginner may struggle to understand, unless it's strictly necessary. So our options are limited by those requirements.

Improving bevy upstream is the best way to improve this template while keeping it simple.

@TheKnarf
Copy link

TheKnarf commented Aug 1, 2024

and 2. not introducing complexity that a relative beginner may struggle to understand, unless it's strictly necessary. So our options are limited by those requirements.

Improving bevy upstream is the best way to improve this template while keeping it simple.

Feels like being able to support both a pause state and a nested settings menu is strictly necessary, but I do get your point.

Personally I think the template should take on the necessary complexity to support at least as much. I'd be happy to make PR, but I won't bother spending time on it if you're unlikely accept it.

@janhohenheim
Copy link
Member

janhohenheim commented Aug 1, 2024

@TheKnarf I would not submit a PR for this yet in your position. I'll keep this in the back of my mind though and talk about it at some point with the Bevy maintainers.

I also want to see a nested settings menu supported, and if the others agree, we may really need a stack.

@will-hart
Copy link
Contributor

I feel like we could get most of the way with just sub-states (although it may be a little ugly). For instance here is a quick attempt at a pause screen main...will-hart:bevy_quickstart:pause-state

@janhohenheim
Copy link
Member

@will-hart can I be inside multiple substates of the playing screen at once?

@benfrankel
Copy link
Collaborator Author

If they're different types then yes. Keep in mind a pause menu is actually two features though, pausing the game and opening a menu, which should use orthogonal state types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants