Coffee-break Tutorials: Pausing Your Game (GML)


Coffee-break Tutorials: Pausing Your Game (GML)

Hello again and welcome to another coffee-break tutorial! This series offers quick and easy tutorials that can be implemented in just a few minutes, with the idea being to teach you some basic coding practices using GameMaker Studio 2 that will be useful to you in your own projects. Today's subject is how to pause your games! Note that this tech blog is for GML users, so if you prefer Drag and Drop™, you should follow the companion tech blog that we've prepared here.

Space Rocks Game

Before continuing, this tutorial uses the finished Space Rocks tutorial project as it's base, so if you're new to GameMaker Studio 2 you should go through that before doing this, although you can download the finished tutorial project from the link below and use that too if you wish:

Download: Space Rocks Finished Tutorial YYZ

If you download the above project, you need to open GameMaker Studio 2 and select "Import" on the Start Page to open it, or simply drag it onto the IDE and drop it, which will show you a prompt to import the project.


SETTING UP

There are various different ways that you can pause a game, but for this tutorial we're going to use one of the simplest, which is to deactivate all the game instances and then draw a "Pause" screen. Deactivated instances still exist in the game, but they're in a kind of "limbo" where they do nothing - they won't draw and they won't run their events. This makes deactivating things ideal for creating a pause system, although it does create a minor issue... since deactivated instances don't draw, the screen goes blank! However, as you'll see, we can fix that!

To get things started, you need to open up the object obj_Game. This is the Space Rocks controller object and it's where we will be making the pause system work. To start with, open the Create Event and add in the following variables:

paused = false;
paused_surf = -1;

obj_Game Create Event

The variable paused will be either true or false depending on whether the game is paused or not, and the variable paused_surf will be used to hold the ID of a surface, which is what we'll use to draw the game to the screen while all the instances are deactivated.


SETTING PAUSED / UNPAUSED

We now need to open up the Step Event of the object obj_Game. There's already code in this event, so we'll add the pause code after what's there already. We'll be using the "P" key to pause the game in this example, but you can use any key really - like escape - or have a button that detectes a mouse click or even detect a gamepad button instead.

The code to add into this event is:

if room == rm_Game
{
if keyboard_check_pressed(ord("P"))
    {
    paused = !paused;
    if paused == false
        {
        instance_activate_all();
        surface_free(paused_surf);
                paused_surf = -1;
        }
    }
if paused == true
    {
    alarm[0]++;
    alarm[1]++;
    }
}

So, here we're checking to make sure we're in the game room, then we check to see if the "P" key is pressed. If it is pressed, we toggle the paused variable using the not operator (!). We then check if it's false (the game was paused, but it's just been unpaused) and if it is we activate all the instances in the room and free the surface that we use for drawing while the game is paused. This part is important, as we don't want to keep the surface in memory if it's not required anymore. Note that we also set the paused_surf variable to -1 again. We do this because we'll be using it as a control for deactivating instances in the Draw Event, which we'll explain in a moment.

The next bit of code in this event is for dealing with the alarms in the controller object. Alarms count down by 1 at the beginning of every step of the game, which means to pause them, we simply add 1 every step while the game is paused! So, we are checking to see if paused is trueand if it is we use the ++ operator to add one to the alarm. This operator is the same as doing:

alarm[0] += 1;
// or
alarm[0] = alarm[0] + 1;

DRAWING THE PAUSE SCREEN

The final thing we need to do now is in the Draw Event of the obj_Game object, so open that now. Again, we already have code in this event, so we will need to insert our pause code into the event, in the case for rm_Game, at the position marked in the image below:

obj_Game Draw Event

We'll break the code to add into two sections to make it easier to follow. To start with, we'll have this code:

if paused == true
{
if !surface_exists(paused_surf)
    {
    if paused_surf == -1
        {
        instance_deactivate_all(true);
        }
    paused_surf = surface_create(room_width, room_height);
    surface_set_target(paused_surf);
    draw_surface(application_surface, 0, 0);
    surface_reset_target();
    }

Here we are checking to see if the paused variable is true and if it is we then check to see if the surface we'll be using to draw instead of instances actually exists or not. If it doesn't we then check the paused_surf variable to see if it's -1 or not, and if it is, we deactivate all the instances except the calling instance which is the game controller (we don't want to deactivate the controller!). Why is this step important? Well, surfaces are volatile which means that things outside the game can destroy them (like minimising the game window), and when that happens the surface_exists() check will return false, but the paused_surf variable won't be -1 (it'll have the ID value of the old surface) and so we won't call the deactivate code again. This means that we will only deactivate objects when the game is paused, and it also means that we can use this section to create other instances after calling the deactivate code - like pause menu buttons or logos or whatever - and they won't be affected by the deactivation.

Next we create our surface and draw the application_surface to it. The application_surface is essentially the "canvas" onto which everything in the game is drawn, so by copying it to the paused surface, we are preserving what is currently being drawn to the screen.

The final bit of code to add goes directly underneath what you've just written and is an else to the check if the paused surface exists:

else
    {
    draw_surface(paused_surf, 0, 0);
    draw_set_alpha(0.5);
    draw_rectangle_colour(0, 0, room_width, room_height, c_black, c_black, c_black, c_black, false);
    draw_set_alpha(1);
    draw_set_halign(fa_center);
    draw_text_transformed_colour(room_width / 2, room_height / 2, "PAUSED", 2, 2, 0, c_aqua, c_aqua, c_aqua, c_aqua, 1);
    draw_set_halign(fa_left);
    }
}

Here all that we're doing is drawing the pause surface to the screen, then drawing a low alpha black rectangle over it to make it look "faded", before finally drawing the text "PAUSED" to let the player know that they've paused the game. Really, you code draw anything here, but this is the simplest thing to do and suits this quick tutorial.

You can run the game now, and in the main game room press the "P" key to pause and unpause the game.

Space Rocks Paused


SUMMARY

That's it for this tutorial! The game has a pause screen, and the code is simple enough that you should be able to add it into your own projects and modify it to suit your needs. Some things you can try that I like to do in my own games are:

  • lower the game music volume a bit when the game is paused, and return to full volume when unpaused

  • add in menu buttons to restart the game, go back to the start screen or quit to desktop (for example)

  • add in some graphic effect when pausing, like gradually dim the surface being drawn, or - if you're feeling brave! - apply a shader to the surface to blur it slightly (I love this effect and use it in my own projects)

Thanks for reading and we hope that this has been interesting and useful to you! If you'd like to see the finished code in the tutorial project without having to actually add it all yourself, or you want to compare what you have with something, you can find download the file below which contains everything we've discussed here.

Happy GameMaking!

Download: Space Rocks With Pause YYZ