Last time, I talked about how triggers can be used to replace traditional step events in order to solve certain esoteric problems in Game Maker. This time I want to explain how to use triggers to achieve something a lot more universally useful: pausing the game.
Game Maker, sadly, has no good built-in methods for pausing that are quite satisfactory (in fact, the documentation doesn't even mention it, except of course the references to the debugging feature). Over the years, I've experimented with the following solutions, but found each of them lacking:
- Solution: Using the
keyboard_wait()
function - Problems: It freezes everything, preventing any sort of pause menu functionality. It also breaks the flow of games designed for controllers or the mouse, because it requires interaction with the keyboard.
- Solution: Going to a dedicated Pause room
- Problems: This is much better, because you can put whatever you want in the pause room to create any kind of effect you want (menus, faded image, soft music, etc). But it's kind of a pain to juggle the
room_persistent
status of the calling room, and if you want to show a frozen image of the game, you have to create the resource yourself using something likebackground_create_from_screen()
. Also, if you want access to any of the objects from the calling room, you're sort of out of luck. - Solution: Using
instance_deactivate_all()
- Problems: This solution uses an object for controlling all pause behaviour that deactivates everything else and takes over until the game is unpaused. It has most of the same problems as the previous solution, though (no access to paused objects; the need to manually create an image resource from the screen), and introduces yet another: Unpausing requires you to call something like
instance_activate_all()
; if there are any objects you don't want to be reactivated, you're out of luck. Basically, this solution is incompatible with any game that has to activate/deactivate instances for any other purpose.
After all this, one starts to wonder why there isn't just some kind of built-in functionality for pausing in Game Maker. Almost all games need the feature (besides notable exceptions like Phantasy Star Online) so why not? There could be a variable called pause_object
which would point to the only object which would remain active while the game was paused (much like how view_object
points to the object which the view should follow). And there'd be a function called game_pause()
that would take one argument - true
or false
- to toggle the state on and off. Would this have been so hard?
Fortunately, with a little bit of work, triggers come to our rescue in this situation, too.
Because trigger events can be set to occur before each step moment (beginning, middle, and end), it's possible to create triggers to completely replace the step events:
(If you can't see the image, the condition code for these triggers should be return global.paused;
).
If you move the actions in the step events on all your objects to the corresponding trigger events instead, you can prevent the execution of these actions merely by setting global.paused
to true
. Any object you don't wish to be paused should retain traditional step events, of course.
Using this method, the draw event will still be executed, preventing the need to generate an image. And all paused objects are still active in case you need to access them. Great!
One quickly notices the drawbacks to this solution, though. Beginning, middle, and end step events aren't the only things that happen for objects during each step in Game Maker. There are other events, like keyboard checking and so on, that are also performed.
This doesn't bother me personally, because I tend to ignore these events and write my own code for checking keys and stuff in the step event of some kind of control object. This isn't for everyone, though, so is there some way to get around this?
Well, yes. You can create more custom triggers that check the same conditions as the original, but also check global.paused
. For example, return global.paused and mouse_check_button_pressed(mb_left);
. This is a bunch of busy work, but do it at the start of your project and it might save you some trouble down the line.
Another drawback to using triggers to pause is that Game Maker handles certain things about objects automatically. Every step, it adds hspeed
to x
and vspeed
to y
, and so on. Again, this doesn't affect me because I use all my own variables, but it can be gotten around anyway: in your code that pauses the game, you could just do this...
...and of course the reverse when you unpause.
In conclusion, I admit that this solution is far from perfect also, and it requires a lot of work to get functioning flawlessly. But depending on what your game is like, and considering the issues with competing solutions, it might be useful to you.
If there are better solutions, I'd love to hear about them.