GameMaker Studio 2 Tip #1: Singletons

Let’s say we had an object PupperManager with the goal of managing all of our game’s Puppers. Since it doesn’t make much sense for more than one thing to manage a group of objects like this, PupperManager is a great candidate for the singleton pattern. You can look up a really computer-sciencey explanation for Singletons, but primarily our goal here is to create an object that fits the following requirements:

  • There’s only one single instance
  • It is globally accessible

Mainting the Requirements

So let’s start with writing PupperManager‘s Create event, this will implement a basic singleton pattern.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
///@desc PupperManager - Create
// declare our singleton's global variable so we don't need to check if it exists
gml_pragma("global", "global.PupperManager = noone;");
if (instance_exists(global.PupperManager)) {
if (global.PupperManager != id)
instance_destroy(id);
exit;
}
// setup our global accessor for ease of use, but also not relying on object name
global.PupperManager = id;
#macro gPupperManager (global.PupperManager)
// initialize pupper manager as normal

Pretty simple, right? I’ll explain some key take aways here:

  • By using the gml_pragma I’m initializing global.PupperManager to noone before anything could possible use it. If I hadn’t done this, then the instance_exist check would look more like :

    1
    if (variable_global_exists("PupperMananger") && instance_exists(global.PupperManager))

    Not the worst, but still, an unnecessary look-up, and this also makes it slightly more dangerous to use our helper macro.

  • We destroy any instances created if an instance already exists. It’s important to understand this behavior, if you rely on any helper create functions, they may need to ensure they’re returning valid instances… though, if you always access via the macro you’ll be safe.
  • We made a macro - by making the gPupperManager macro, anywhere we want to use the PuppyManager we can use with(gPuppyManager) and have no risk of error - however, if the singleton hasn’t been created, this is the same as with(noone)

Before we go - it’s important to also Clean Up after yourself:

1
2
3
///@desc PupperManager - Clean Up
if (global.PupperManager == id)
global.PupperManager = noone;

Reset the global handle, that way if your singleton isn’t persistant, it won’t block new ones from being generated.

And that’s all there is to it! Let me know in the comments if you’ve got any questions, or if anything can be explained more clearly. Stay tuned for more GMS 2 Tips!