How to elegantly create pause state?

Hi there,
I’ve got a game state system like so:

pub enum GameState {
    One(OnePlayerData),
    Two(TwoPlayerData),
    Pause(Box<GameState>),
}

And all that I do when I’m in Pause is I draw the internal game state, and a gui over it, but don’t update the internal game state. This is great, until I come to this kind of pattern:

match self{
    //.....
    Paused(paused_data) => {
        if match_all_unpause_conditions {
            *self = *paused_data;
        }
    }
}

Where stuff kind of breaks, logically. I can’t use std::mem::swap because I can’t borrow self as mutable more than once, and cloneing or copying self would not be viable. How might I implement a Pause state in a nice and idiomatic way, such that I can swap in and out of the Pause state? Thanks!

Why do you need to store the game state inside the game state? Why not just have a flag outside that tells that the game is paused and limit access through that outer struct.

i.e.

struct GameState {
    state: PlayerData,
    is_paused: bool
}

enum PlayerData{
    One(OnePlayerData),
    Two(TwoPlayerData),
}

Then you can limit access to PlayerData through GameState.

Also you could split your update and render functions, and call them separately.

fn update(game_state: &mut GameState) { /* ... */ }
fn render(game_state: &GameState) { /* ... */ }

This will guarantee that you won’t change the GameState while rendering, only while updating.


Another thing to consider is using generics, if OnePlayerData and TwoPlayerData have the same surface API (or mostly the same surface API), then you could define that API via a trait

trait PlayerData {
    // common functionality
}

struct OnePlayerData {
    // stuff in here
}

impl PlayerData for OnePlayerData {
    // ...
}

impl OnePlayerData {
   // functions special to OnePlayerData
}

struct TwoPlayerData {
    // stuff in here
}

impl PlayerData for TwoPlayerData {
    // ...
}

impl TwoPlayerData {
    // functions special to TwoPlayerData
}

struct GameState<Data: PlayerData> {
    player_data: Data,
    is_paused: bool,
}

Excellent idea, the trait and the flag-struct combo would go great together, I’ll implement this. Thanks so much!

I will second @RustyYato’s suggestion to break out the pause flag. However, if you find yourself facing this situation in the future and are adamant of finding a workaround, you can always consider using somethin like replace_with.

One more small question, if I have a Box<dyn PlayerData> and I want to run the associated trait functions, I can do that through the magic of Deref, self.player_state.draw() for example. If I do that, I never have to worry about it moving the internal dyn PlayerData around right? Because I don’t want to be copying (or moving) a potentially large struct around 60 times a second.

Box is just a pointer, and you won’t be moving the data stored on the heap that the Box points to around at all. It is very fast to move a pointer, (just 64/32 bits of stack/register memory).

1 Like

Thanks for the fast reply! Oh okay, so I can use it without worrying about speed, sweet!

Oof, unfortunately I can’t have a dyn Trait object who’s functions are independently generic :confused: I guess I’ll have to scrap the dyn idea…

Dynamic dispatch from trait objects can be slow due to missed optimizations (such as those from inlining functions), if you want performance, try and refactor your code to use generics instead. Also allocations are expensive, so try and limit it, especially in tight loops.


For example, do you need to handle OnePlayer and TwoPlayer in the same GameState? Could you handle them separately?

Both of them implement PlayerState which has draw, update etc., so it would be more logical to handle them both in the same place, such as the GameState, which would automatically call draw, update, etc, when necessary.

Ah, perhaps I could have an Option<T> for both, and just keep a flag, since I have so few options, and don't want to worry about enum impls that would have to worry about both

Could you make GameState generic?

struct GameState<Data: PlayerData> {
    data: Data,
    // ... other fields
}
player_state: OnePlayer::new(),
---------------------------------
note: expected type `Data`
     found type `...::OnePlayer`

Unfortunately not

Do you have the code on git? It would be easier to help if I can see it.

in the trait PlayerData you can create a function new

trait PlayerData {
    fn new() -> Self;
}

and in GameState you can call like like so Data::new().

Ah, okay, let me commit, and I’ll implement that! Here’s my repo, and here’s the file I’m talking about
Unfortunately, that doesn’t work still… :frowning:

Yeah, so put all the functionality that is common between OnePlayer and TwoPlayer and put it in PlayerData. So that would be update, ‘handle’ and render as you already have, and new.

It’s giving me the same complaint about it not being a PlayerState. I’m pretty sure that a generic type can’t change its generic parameter though, because that would make it non-Sized
Already pushed commit

Yes, a generic type cannot change it’s type.


you didn’t change OnePlayer::new() to Data::new()

1 Like

Ohhhhh, I see! So, when I want to change the kind of PlayerState that I hold, I just return a new GameState, that’s excellent! Thanks a bunch!

Oh, by the way, I ended up implementing it a bit differently than what we worked on, here is the new version.