GMS 2 What is the best way to pause a game?

I am making a platformer, what I do is just place a solid object on top of the player to stop them moving and the same for every enemy. And then I use a draw event in my controller object to draw a seethrough rectangle with the different options. What would be the best way to save the game without changing how it looks behind the rectangle? (I like how the rounded rectangle looks).

If it helps my code is the same as Shaun Spalding's shooting platformer tutorial series without the shooting part and with a few modifications.
 

samspade

Member
It really depends on what your game is like. I think the most straightforward way is to deactivate instances. You can save the current image to a surface and display that if you would like. Both of these things can be accomplished with a few lines of code and is very stable which is why I prefer it. However, it doesn't work if you need elements of your game world to run in the background. In this case, there's really no way around building a 'paused' state into every object that needs to be paused.


Here is the basic deactivate instances idea - when you want to pause create a pause object with the following code and when you want to unpause destroy that object:

Code:
/// Create Event of Pause Object
instance_deactivate_all(true);
...reactivate the objects you need active if any

/// Destroy Event of Pause Object
instance_activate_all();
I generally have objects that should be paused as part of a controller class and then I do this:

Code:
/// Create Event of Pause Object
instance_deactivate_all(true);
instance_activate_object(controller_parent);

/// Destroy Event of Pause Object
instance_activate_all();
If you want to build a pause state into objects, then I would do it with user events. Then when you want to pause you can do this:

Code:
//pause
with (all) {
    event_user(0);
}

//unpause
with (all) {
    event_user(1);
}
The reason this is nice is that you can call event_user even if that event doesn't exist and the event will be specific to that object meaning that you can control how each object pauses (by giving them their own user event) and whether they pause at all (by not giving them those user events). What the code to pause would look like depends entirely on what your code already looks like.
 
It really depends on what your game is like. I think the most straightforward way is to deactivate instances. You can save the current image to a surface and display that if you would like. Both of these things can be accomplished with a few lines of code and is very stable which is why I prefer it. However, it doesn't work if you need elements of your game world to run in the background. In this case, there's really no way around building a 'paused' state into every object that needs to be paused.


Here is the basic deactivate instances idea - when you want to pause create a pause object with the following code and when you want to unpause destroy that object:

Code:
/// Create Event of Pause Object
instance_deactivate_all(true);
...reactivate the objects you need active if any

/// Destroy Event of Pause Object
instance_activate_all();
I generally have objects that should be paused as part of a controller class and then I do this:

Code:
/// Create Event of Pause Object
instance_deactivate_all(true);
instance_activate_object(controller_parent);

/// Destroy Event of Pause Object
instance_activate_all();
If you want to build a pause state into objects, then I would do it with user events. Then when you want to pause you can do this:

Code:
//pause
with (all) {
    event_user(0);
}

//unpause
with (all) {
    event_user(1);
}
The reason this is nice is that you can call event_user even if that event doesn't exist and the event will be specific to that object meaning that you can control how each object pauses (by giving them their own user event) and whether they pause at all (by not giving them those user events). What the code to pause would look like depends entirely on what your code already looks like.

Thank you! I will try this ASAP!
 
It really depends on what your game is like. I think the most straightforward way is to deactivate instances. You can save the current image to a surface and display that if you would like. Both of these things can be accomplished with a few lines of code and is very stable which is why I prefer it. However, it doesn't work if you need elements of your game world to run in the background. In this case, there's really no way around building a 'paused' state into every object that needs to be paused.


Here is the basic deactivate instances idea - when you want to pause create a pause object with the following code and when you want to unpause destroy that object:

Code:
/// Create Event of Pause Object
instance_deactivate_all(true);
...reactivate the objects you need active if any

/// Destroy Event of Pause Object
instance_activate_all();
I generally have objects that should be paused as part of a controller class and then I do this:

Code:
/// Create Event of Pause Object
instance_deactivate_all(true);
instance_activate_object(controller_parent);

/// Destroy Event of Pause Object
instance_activate_all();
If you want to build a pause state into objects, then I would do it with user events. Then when you want to pause you can do this:

Code:
//pause
with (all) {
    event_user(0);
}

//unpause
with (all) {
    event_user(1);
}
The reason this is nice is that you can call event_user even if that event doesn't exist and the event will be specific to that object meaning that you can control how each object pauses (by giving them their own user event) and whether they pause at all (by not giving them those user events). What the code to pause would look like depends entirely on what your code already looks like.

Really late, but how would you save an image to a surface and then display it?
 

NightFrost

Member
Really late, but how would you save an image to a surface and then display it?
When you detect that game is paused, create a surface that is equal in size to your application surface, then surface_copy application surface into that. One of your objects that has not been deactivated then needs to draw this to screen - in my projects, that's my display controller object. In Post Draw event, just draw out the surface, as default draw target has switched to your display. Then, when you detect unpause, destroy the surface. The downside of using a pause surface is if you lose the surface, you get just a black screen besides whatever pause menu you are creating, as you can't recreate the content with all your game instances being deactivated. Turning the pause image into a sprite might be a good idea, but then you really need to remember to destroy the sprite afterwards to avoid memory leak.

(To expand on the draw thingie: during normal draw event operations, draw target is by default the application surface, and by default it is automatically drawn to your display once it is finished. However once post draw event is reached, the default target switches to display device, in case the code needs to do some fullscreen post-draw processing. This makes it the most convenient place to draw out the paused game image.)
 

Kezarus

Member
I got problems when I copy the surface because of the GUI. Then I take a print screen, save to disk and open as a sprite. It's a bit slow, but it copies everything on the screen. Is there a better way of doing this?
 
AFAIK you can go directly from a surface to a sprite - this is what I do on my current project.
Code:
screenshot = sprite_create_from_surface(pause_surface,0,0,surface_get_width(pause_surface),surface_get_height(pause_surface),false,false,0,0);
You can reference 'screenshot' like you would any other sprite.
 

Kezarus

Member
AFAIK you can go directly from a surface to a sprite - this is what I do on my current project.
Code:
screenshot = sprite_create_from_surface(pause_surface,0,0,surface_get_width(pause_surface),surface_get_height(pause_surface),false,false,0,0);
You can reference 'screenshot' like you would any other sprite.
Hi @DiamondWolf ! The problem is, when you copy the surface like that, the GUI is not drawn in it. If you have buttons that you don't want to be pressed when paused, but have to appear as disabled.

I have a solution, but it's a bit slow and I would like to improve it.

Code:
screen_save("PausedScreen.png");
pauseScreenShot = sprite_add("PausedScreen.png", 1, false, false, 0, 0);
file_delete("PausedScreen.png");
 

NeutronCat

Member
I got problems when I copy the surface because of the GUI. Then I take a print screen, save to disk and open as a sprite. It's a bit slow, but it copies everything on the screen. Is there a better way of doing this?
Make the object that draws GUI still active while the game is paused?
 

Azenris

Member
Maybe after you draw the surface, set that surface as the target and force draw the gui on that surface.
Code:
with ( all )
   event_perform( ev_draw, ev_gui );
Maybe something to that nature
 
Just out of curiosity why not just use the application surface instead of making a new one? The application surface should be separate from the GUI. If you have intertwined the application surface and the GUI together in a bad way then you could simply set a pause flag in the gui objects and when it's set they are to be hidden. This way you could still use application surface. If your creating a separate sprite everytime you pause the game I feel like that is not a good idea. Maybe I am wrong, but using the application surface seems like the best way or am I missing something?
 

Kezarus

Member
Just out of curiosity why not just use the application surface instead of making a new one? The application surface should be separate from the GUI. If you have intertwined the application surface and the GUI together in a bad way then you could simply set a pause flag in the gui objects and when it's set they are to be hidden. This way you could still use application surface. If your creating a separate sprite everytime you pause the game I feel like that is not a good idea. Maybe I am wrong, but using the application surface seems like the best way or am I missing something?
So, the problem is as I stated above. When you capture the application surface it does not have the GUI drawn in it. I will try to do what @Azenris proposed.

About the sprite, there is no problem if you handle it and destroy it when it's not needed anymore. But, sure, if you are not careful, it can create a huge memory leak. I did a standard function to handle that. The only issue is speed (about a quarter of a second). Will try that solution and come back here. =]


Cheers!
Kezarus
 

Kezarus

Member
Maybe after you draw the surface, set that surface as the target and force draw the gui on that surface.
Code:
with ( all )
event_perform( ev_draw, ev_gui );
Maybe something to that nature
Nice try, but didn't work. This is a little tricky to do, thanks for the suggestion! =]
 
Top