Remix.run Logo
qwery 2 days ago

Like a lot of issues in gamedev, pausing the game is a surprisingly difficult problem to solve. It's especially difficult to provide a one size fits all solution which would obviously be desirable for the popular modern engines that try to be a general solution.

I see a lot of comments here saying something along the lines of "isn't it just a state in the state machine?" which isn't wrong, but is an extremely simplistic way of thinking about it. In, say, 1983, you could get away with something like that:

- pause the game: write "PAUSED" to the tilemap

- paused main loop: check input to unpause

- unpause the game: erase the "PAUSED" / restore the previous tiles

But at that time you could already see the same sort of issues as today. Something somewhat common in Famicom/NES games is the sprites disappearing when the game is paused. Perhaps deliberate/desirable in some cases (e.g. Tetris) but a lot of the time, probably just a result of the 'is paused' conditional branch in the main loop skipping the sprite building code[0].

There's an extremely large problem space and ultimately, each game has its own way to define what "paused" actually means.

You might be interested in the features Godot provides[1] for this. Particularly, the thing that makes it interesting is the 'process mode' that each node in the scene tree has. This gives the developer quite a lot of control over what pausing actually means for a given game. It's not a complete solution, but a useful tool to help solve the various problems.

[0] Simplified description of course. Also, the sprite building code often ended up distributed throughout the various gameplay logic routines, which you don't want to run in the paused state.

[1] https://docs.godotengine.org/en/stable/tutorials/scripting/p...

[ed] Just adding that Tetris is only an example of a game where you might want that behaviour, not a comment about how any of the Tetris games were actually made.

an0malous 2 days ago | parent [-]

I read your comment and the article and I’m still not really clear on why this isn’t as simple as saving the current state or pausing the render or time loop.

qwery a day ago | parent | next [-]

The short answer is: because of all the complexity that you're not seeing. I'll try to explain:

My '1983' example above is a simple way to implement a pause state -- when the game is paused, don't run the game logic. The sprites disappearing that I described (a real quirk, if not a bug, of games of that era) is a side effect of that. The sprites disappear because the set of objects to draw each frame is determined by the game logic, which is being skipped in order to pause the action.

Is it wrong that the game logic submits the drawables? I would say that it's inflexible, but not wrong. After all, the sprites are representing the state of the game, so they must be derived from it in some way.

You can do more engineering to support a more robust & elegant pausing system. You can build that system such that pausing the game feels like simply "pausing the loop". But that's more code, more complexity, less simple.

I'm not exactly sure what "pausing the render loop" means to you, but let me ask you this: how do you render the pause menu? When there is no time passing, how does the little bouncy cursor in the menu continue to bounce?

You'd want sound effects to pause while the game is paused, and ideally resume from where they were when the game is unpaused. But does the pause menu make sounds? Is there music? Does the pause menu play different music or continue the in-game music?

And this is the most obvious, simplistic idea of what pausing the game is -- to show a pause menu. What about in-game cutscenes: do the NPCs in the background keep running around while you're talking to another one? Inventory management: the items the player has are a gameplay system but you access it while the game is paused?

This pattern applies to every system in the game. You can't just cut out the xyz altogether, you need a sufficiently complicated xyz system in order to simply pause what you want to pause.

jayd16 2 days ago | parent | prev | next [-]

Saving the current state? What does that even mean? You don't save transient things like visual particle positions but it's something you expect to persist between pauses.

Pausing the render? But not the physics so you keep falling? You need to pause many systems. At the very least you'd want to pause gameplay, and sound and physics. You'd want to keep input and some of the UI unpaused. If you have a fancy UI with VFX, you need to make sure those are not using the paused game time. etc etc

glenneroo 2 days ago | parent [-]

And if you pause sound in Unity using AudioListener.pause = true, which is supposed to make life easier, but ends up being useless if changing settings/clicking buttons has audio feedback, or changing the volume has audible feedback to tell you how loud, or you allow to change voice style, and on and on.

Repeat that for every system - all those edge cases for each system can waste a lot of time and energy.

dwaltrip 2 days ago | parent | prev [-]

It’s only simple if your state machine has zero implicit state and all transitions are perfectly and precisely articulated. Good luck with that!

P.s. And once you are done achieving the above, you can then make sure you haven’t caused performance issues :)

But yes, conceptually, it’s a relatively simple idea. The devil is always in the details.