GM:S 1.4 How can I make the Pause function in my game?

Discussion in 'Programming' started by Ziliock, Jun 25, 2016.

Tags:
  1. Ziliock

    Ziliock Guest

    In game maker 8 it was simply with ATL but in Studio I can figure it out.
     
  2. Jordan Robinson

    Jordan Robinson Member

    Joined:
    Jun 22, 2016
    Posts:
    86
    In Studio, you have to make a pause function from scratch - you could have a variable called isPaused in all of your moving objects, and check this before they are allowed to move. But this isn't very flexible and making changes later on may be difficult. It could work for a small game, though.

    I've also seen some people instance_deactivate_all() which will stop everything, and then you can overlay a separate screen that says "paused". If you wanted to still see the game in the background using this method, you would have to use surfaces and draw a "snapshot" of the view just before you deactivated all of the instances.
     
  3. wamingo

    wamingo Member

    Joined:
    Jun 21, 2016
    Posts:
    57
    if (global.paused) exit;
    is an option
     
    Jordan Robinson likes this.
  4. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    1,922
    There's several things you need to note when you want to put in pause functionality. You want the exit check as given above on every game object that acts out on screen, but you must also realize that animations will continue to animate and alarms continue to count down independently. You need to bump up all running alarms so they don't fire and zero all animation speeds while game is paused. Because of this, you have to have object's animation speed stored in a separate value you can later retrieve it from.

    I do it by first creating the following PauseCheck script:

    Code:
    if(global.Paused == true){
        for(var i = 0; i <= 11; i++){
            if(alarm[i] > 0) alarm[i]++;
        }
        image_speed = 0;
        return true;
    } else {
        image_speed = AnimationSpeed;
        return false;
    }
    Where global.Paused is the pause flag and AnimationSpeed refers to object' s current animation speed. Then in every object that requires pausing I call at the first line of step event:
    Code:
    if(PauseCheck() == true) exit;
    Why do exit outside the script? Because should the exit command be inside the script, it merely exits the script and continues running the code of the calling object. The exit must be in the main step event code to properly exit.
     
    Last edited: Jun 26, 2016
    Iodinex64 and Askhat like this.
  5. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,556
    You could make the room persistent, then change to another room that acts as the pause menu, and then when you change back, you turn off the room's persistence again. It's not the best overall solution, but it's very easy to set up and pretty useful for games where you have a very advanced menu system.
     
    blue apple, GreenSmurf and Snail Man like this.
  6. Snail Man

    Snail Man Member

    Joined:
    Jun 20, 2016
    Posts:
    282
    If you want the paused screen to show the game in the background, you could have the game take a screenshot right before leaving the gameplay room, then import and draw it in the pause menu background. Don't forget to programmatically delete it afterwards though!
     
  7. L0v3

    L0v3 Guest

    The way I deal with pausing is having a pause layer value for every object, similar to a depth value. Then check for every interaction event something like this:
    Code:
    // Everything above here will be run no matter what.
    
    if (global.pause > pause_layer) exit;
    
    // Everything below here will not be run if paused.
    
    Repition of code will be minimized with proper parentiage of objects, but yes, it have to be implemented for everything. The layering of pause is useful for having UI-Objects ontop of eachother, pauseing the underlying views.
     
  8. RangerX

    RangerX Member

    Joined:
    Jun 20, 2016
    Posts:
    2,587
    What I do is the following:

    - Take a picture of the game to make a background with. (using "sprite_create_from_surface()")
    - Deactivate everything except my Pause Menu object.
    - Now you display the picture of the game as background, your menu on top.
    - To unpause, I reactivate everything.
    - Kill the menu and background.
     
    chirpy, TheRBZ, GreenSmurf and 2 others like this.
  9. SoulTie

    SoulTie Guest

    I usually do pretty much exactly what RangerX has suggested with a few minor differences.
    1. I copy the application surface to "global.pauseSurface" so that I can deactivate application surface drawing. This helps me boost mobile game performance
    2.Use the control object to deactivate everything and then create an instance of oPause.
    3. use oPause to draw global.pauseSurface with a blur shader
    oPause contains the pause menu. When you unpause the game,
    the control object reactivates everything, including application surface drawing, destroys oPause, and frees the pause surface
     
  10. If you want a quick (but limited) solution, you can do it with a while loop:

    Step Event:
    Code:
    /// HOLD a button to pause the game
    
    var pause=false;
    
    if (keyboard_check(vk_space)==true)  // or the button you want
       pause=true;
    
    while(pause==true) // infinite loop
       {
       if (keyboard_check_direct(vk_space)==false)
          pause=false;
       }
    
    This causes the game to pause everywhere, because the game stuck at the while loop.

    Additionally you can draw something to the screen like "Pause", but this must one step before the step of the while. (the code needs some additions then)

    However, this has its limitations, like you can hardly handle user input and delta time stuff must be considered. I would not recommend this method.
     
    Last edited by a moderator: Jun 27, 2016
  11. Ziliock

    Ziliock Guest

    Thanks you.Can you translate it to Drag'n Drop or very specific GML(Codes)?
     
  12. Ziliock

    Ziliock Guest

    Thanks you!How can I do that in Drag'n Drop? Or GML, but I'm terrible at GML(Codes) a very specific explanation would help
     
  13. FatalSleep

    FatalSleep Member

    Joined:
    Jun 21, 2016
    Posts:
    34
    The easiest option is this...

    It's super easy to create a pause menu if you use room persistence. The basic idea is that when you pause you set the current room to be persistent and then you change rooms to a "pause room," e.g. a room that acts as the pause menu. Then when you un-pause you change rooms to the room you where in before you paused and then you turn off room persistence.

    Room persistence--if you don't already know--tells GameMaker to store everything that's happened in a room in memory so that when you leave the room and come back, the room is just the way you left it.

    To do this you'll need 2 things:
    • A global variable to store the current game room.
    • A room that acts as the pause menu.

    (Skip step 1 if you do NOT need a screenshot of your game to display behind the pause menu)...
    1. Create a screenshot of the game via the application surface.
      Code:
      // The game always draws to the "application_surface" (see docs for more info).
      var width = surface_get_width(application_surface),
          height = surface_get_height(application_surface);
      
      // This will create a sprite from the application surface, which will be the screenshot of the game.
      global.PauseScreenShot = sprite_create_from_surface(application_surface, 0, 0, width, height, false, false, 0, 0);
      
    2. Set the current room persistence to TRUE.
      Code:
      room_persistent = true;
      
    3. Change rooms to the pause room.
      Code:
      global.RoomBeforePause = room;
      room_goto(room_pause);
      
    When you un-pause do this...
    1. Changes rooms to the previous room we where in before we paused.
      Code:
      room_goto(global.RoomBeforePause);
      
    2. When we've switched to the old room after un-pausing:
      Code:
      // Only run the un-pause code if we actually un-paused.
      if (global.RoomBeforePause != -1) {
          global.RoomBeforePause = -1;
      
          // Only do this if you--skipped step 1--created the pause screenshot of the game.
          sprite_delete(global.PauseScreenShot);
      }
      
     
    Last edited: Jun 27, 2016
  14. Ashraf Hamdi

    Ashraf Hamdi Member

    Joined:
    Aug 19, 2016
    Posts:
    38
    very helpful topic, thanks
     
  15. Soulie

    Soulie Member

    Joined:
    Jun 25, 2016
    Posts:
    23
    I'm looking to use this method to pause my mobile game as I think it might be good for tutorials too. Thanks!

    I was wondering, if we are copying the application surface to a different surface (pause surface) then that new surface is volatile, right?
    So we'd need to be careful about people going out of the game and coming back on mobiles?

    Also :

    • Should we destroy the pauseSurface when we unpause to save memory? Or keep it?
    • When copying the application_surface to pauseSurface, the tiles in my room get placed on top of my other sprites instead of behind them. Any ideas why this might be?
    Thanks for any help

    *Edit*

    I managed to sort out the problem with the tiles. They were getting drawn on top of the whole surface, so they just need disabling too with tile_layer_hide() when showing the pause menu.
    Then tile_layer_show() on unpause.
     
    Last edited: Aug 27, 2016
  16. RangerX

    RangerX Member

    Joined:
    Jun 20, 2016
    Posts:
    2,587
    If you don't want to lose your "pause surface" that IS volatile, save your screen as a sprite like my method and not a surface.
    Flush your sprite or surface based pause background as soon as the player unpauses.
     
    Soulie likes this.
  17. Soulie

    Soulie Member

    Joined:
    Jun 25, 2016
    Posts:
    23
    Thanks RangerX,

    Btw, when you say flush the surface/sprite do you mean destroy/free it from memory?
    E.g. surface_free()?
     
  18. RangerX

    RangerX Member

    Joined:
    Jun 20, 2016
    Posts:
    2,587
    Yes. If its a surface, use surface_free. If its a sprite, sprite_delete. If its a background, background_delete.
     
  19. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,556
    One approach I use for simplicity sometimes is to deactivate all objects (apart from the pause controller), but also create special 'placeholder' objects for every visible object that also has a sprite, who gets the same sprite, image (but no image_speed), scales, rotation, blend and alpha as the things they're stand-ins for. Uses a lot less VRAM than creating a visual resource on-the-fly, so it might be more compatible or something, too. (It's less effecient when you have more instances, but since they don't actually do anything and GM now skips empty events, it shouldn't be too bad).
     
  20. J_C

    J_C Member

    Joined:
    Jul 28, 2016
    Posts:
    35
    This looks like a cool solution. I have one question, didn't you forget to draw the global.PauseScreensShot in the Pause room?
     
    Last edited: Sep 8, 2017
  21. Tornado

    Tornado Member

    Joined:
    Sep 9, 2016
    Posts:
    471
    I'm doing like @RangerX.
    Deactivating objects and showing the screen shot either via application surface screenshot or via file screen shot depending on whether I want HUD (drawgui) in the screenshot or not.
    This works perfect even for physics objects. after unpausing they resume their previous momentum.

    The idea with persisting rooms is also nice. Does that also work with physics objects like I described above?
     
    Last edited: Sep 6, 2017
  22. Tornado

    Tornado Member

    Joined:
    Sep 9, 2016
    Posts:
    471
    I would like to understand that, can you please explain it for a surfaces noob? Why do you deactivate application surface? How does it boost performance, I mean we are in pause mode just showing a screenshot, what performance do we boost here?

    Where do you draw pause screen, after application surface is deactivated? Why bother?

    thx
     
    Last edited: Sep 6, 2017
  23. RefresherTowel

    RefresherTowel Member

    Joined:
    Jul 13, 2016
    Posts:
    1,211
    If you're drawing the pause stuff to a new surface then deactivating the application surface won't affect the drawing of the pause stuff (application surface and a surface you create are two different 'screens' so to speak). As to the performance boost, the game will still be drawing application surface if you're simply drawing another surface over the top of it (i.e. the game is basically rendering two screens at once), so deactivating the application surface boosts performance as it removes the unnecessary drawing event. At least, that's what's happening to my limited surface knowledge.
     
    Tornado likes this.
  24. Tornado

    Tornado Member

    Joined:
    Sep 9, 2016
    Posts:
    471
    aha ok, thx for the clarification. I guess the real benefit will be reducing cpu/gpu usage, thus reducing heating and battery consuption for mobile devices.
     
  25. J_C

    J_C Member

    Joined:
    Jul 28, 2016
    Posts:
    35
    Ok, so I have used this method and it was so easy and fast, and it works perfectly (for now). I definitely recommend this method for a pause menu.
     
  26. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,556
    When you use room persistence, keep in mind that entering a persistent room gives all objects a Room Start event (even though the room has already "started" way back). If you're not aware of this it can lead to problems later (if you use Room Start to initialize stuff etc). Also, the Room / Instance creation code is not run. Woo, consistency.
     
    Tornado likes this.
  27. Tornado

    Tornado Member

    Joined:
    Sep 9, 2016
    Posts:
    471
    Thx for pointing it out Yal. I never even noticed there is such event.

    But I would say it is actually consistent.
    The room is created just once, but can be "started" all over again with room_goto. I know the term "starting" can be misleading, but I guess it is hard to find a better term.
    Maybe it would be "room enter event" :)
     
  28. Richirams

    Richirams Member

    Joined:
    Sep 9, 2016
    Posts:
    34
    Hello, sorry i necro this post but i was looking for a way of doing a pause menu and i liked this method, i only have one problem tho, how or where do i change the room's persistance back to false? I ask because in my pause menu i have a button that takes me back to the main menu and then, if i go back to that same room it is still persistent.
     
  29. CMAllen

    CMAllen Member

    Joined:
    Mar 2, 2017
    Posts:
    855
    Nah. Copy the "pause surface" to a buffer. If the surface is lost, you can regenerate it from the buffer. It's the same effect, but you don't need to worry about extra texture pages and extraneous sprite data floating around. Buffers are non-volatile, so you don't need to worry about them disappearing randomly. You just need to be sure you clean it up at the same time you clean up the pause surface.
     
  30. RangerX

    RangerX Member

    Joined:
    Jun 20, 2016
    Posts:
    2,587
    All true. But maybe not worth the assle as having one texture page more while your pause menu is opened will probably not slowdown your game. And the pause menu probably doesn't cause much texture swaps so here again, both solutions are clearly viable.
     
  31. Ted Gress

    Ted Gress Member

    Joined:
    Sep 1, 2016
    Posts:
    749
    Ok. So I set perstient = false in the object that you click to exit the store. It still works on entry and hangs on exit, That is, the game freezes and turns white.
     
  32. OblivionSkull21

    OblivionSkull21 Member

    Joined:
    Sep 26, 2017
    Posts:
    300
    The easiest way is to create a fully opaque pause screen, that way you don't have to worry about making objects "stand still" in the background.
    Otherwise, you'd have to mess with the speeds of the objects using variables.

    Code:
    if global.paused{
    image_speed = 0;
    speed = 0;
    }
    would go inside any object you don't want to move while paused.

    You'd also have to pause alarms as well.

    For the sake of difficulty, I do the easier way.

    Create an obj_pause.
    In the create event, use a variable:
    Code:
    global.paused = false; //the game defaults to NOT PAUSED
    In a step event:
    Code:
    if keyboard_check_pressed(vk_escape){ //or whatever key activates the pause screen
    
    global.paused = true;
    }
    
    if global.paused{
    instance_deactivate_all(true); //this deactivates all objects except the pause screen itself
    }
    
    if global.paused && keyboard_check_pressed(vk_escape){ //resume the game
    
    global.paused = false;
    instance_activate_all();
    }
    Finally, in the draw event:
    Code:
    if global.paused{
    
    draw your pause menu here.
    
    }
    If you want other functions available in the pause screen (i.e. quitting the game), you'll have to register those with key presses inside the step event under if global.paused.

    If you want background music to stop playing while paused, add audio_pause_sound as well. Then, audio_resume_sound when you're done.
     
  33. Ted Gress

    Ted Gress Member

    Joined:
    Sep 1, 2016
    Posts:
    749
    There has to be a quicker way than doing a check for a pause variable for every object. I would be doing one hundred checks.Why not use the persistent method? It seems to have worked for some people.
     
  34. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,556
    Let me just point out a thing I noticed.

    upload_2018-9-26_19-24-6.png

    Please make a new topic instead of necro-bumping an old one if there's not been any replies in 3 months.


    If the game crashes (white window + not responding anymore) it's likely an infinite loop somewhere. Check for those, a common one is to put instance_destroy() in the Destroy event (which causes the instance to destroy itself a second time, running the destroy event again - you get the picture).
     
  35. Death

    Death Member

    Joined:
    Aug 8, 2018
    Posts:
    81

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice