Category: Tutorials

GameMaker Studio Tutorial: Getting Into Shaders

Shaders have been a part of GameMaker Studio for a while now, having been introduced in 2014. Since their inclusion, I have mostly remained mystified by them, with a vague and cloudy understand of what they are and what they can do, and haven’t used them at all. That will [hopefully] start to change today.

As always, when try I learn something new in programming, I find that writing up what I’ve learned helps me to remember and keep my learning organized. I like to publish my notes so that they can help others, and so that others can find errors and make suggestions for better ways to do things. I’m still very new to working with shaders, so I’m not trying to put myself out there like I’m some kind of expert, but here’s what I’ve been able to learn about using shaders with GameMaker Studio so far:

Shader basics

First, we need to understand what a shader is. A shader is a specialized program that processes graphics. Shaders are executed on the Graphics Processing Unit, or GPU, which is specialized hardware for accelerated graphics processing. Thus, shaders are very fast. As well, since they work on the GPU, using shaders will free up the CPU to do other tasks, which can further help to improve the frame rate of your games.

This sounds like enough of a reason to want to use shaders, doesn’t it? Well, it gets better. The main thing about shaders is that they can do amazing visual effects, which will can make your game look better, but can also play an active role in how the game plays. For example, you could use a shader to handle the graphical processing of a special view mode in the game, such as night vision or x-ray vision. One of my favorite shader-based gameplay mechanics that was centered on the use of shaders was Daniel Linssen’s Birdsong, winner of the “Overall” and “Theme” categories of the Ludum Dare 31 compo held in 2014. The theme of LD31 was “Entire Game in One Screen”, and Linssen’s approach to this was to create a giant one-room game, that was crammed into a single screen(no scrolling), and, using a fish-eye lens effect done with a shader, magnify the area where the player is so that it was large enough and detailed enough to be playable.

There’s virtually no limit to what graphical effects you can come up with using shaders, other than the limits of your imagination and of course your programming and math skills. It also helps to understand how computers work with graphical concepts such as color, pixels, binary math, and so forth. Additionally, scientific knowledge in disciplines like optics can be very useful. Shaders have their own specialized programming language that they are coded in — actually there are several related languages to choose from. Because of this, shaders are considered an advanced topic in programming, and there are numerous hurdles to surmount in order to be able to write them yourself.

That said, shaders are re-usable bits of code, and so one of the first things you can do when you start getting into shaders is to simply use pre-existing shaders that have been written by other people.

Getting Started with Shaders

Before you can use shaders, you’ll want to familiarize yourself with a few concepts.

Shader references

Here’s links to the relevant pages in the GMS manual on using shaders in the context of GameMaker Studio:

GMS1:

Shaders Overview

Shaders GML reference

Shader Constants

Tech Blog Shaders tutorial: 1 2 3 4

GMC Forums shader tutorial.

GMS2:

Shaders Overview

Shader Constants

 

Other shader resources (general)

Language References

The four shader languages that GMS supports are: GLSL ES, HLSL9, HLSL11, and GLSL. Which one you need to learn and use will depend on your target platform, but for this article we’ll focus on GLSL ES, since it supports the most target platforms (all of them, except Windows 8).

GLSL ES language specification

HLSL language specification

I haven’t gotten into the shader languages enough yet to know why you’d ever pick HLSL over GLSL, but presumably there must be some advantage to using HLSL when targeting Windows platforms, either in terms of correctness or performance. Otherwise, I would think you’d be better off just sticking with GLSL ES and be compatible with the most targets.

Tools

Shadertoy Shadertoy is a wonderful website that allows you to play with shader programming, running them in your web browser. Then you can share your shader creations with the community of users of the website, and in turn you can demonstrate and use shaders written by others.

Other graphical concepts in GameMaker, and how they relate to shaders

It’s not a bad idea to review and understand the entire chapter on Drawing in the GameMaker documentation. There are many concepts that you will need a working knowledge of in order to understand how to use drawing to its fullest capacity, and to get things working together smoothly.

But the manual isn’t the end of the story. Often I find that the manual doesn’t go far enough to explain how different concepts work. The sections on blend modes and alpha testing are particularly inadequate by themselves. The manual also doesn’t go very far to demonstrate or suggest how different features and functions can be connected to one another. That’s for the user to infer, and verify through experimentation. This is great if you are creative and love to experiment and discover. On the other hand, there’s so much that has already been figured out and discovered by others, and it would be nice if that was all documented in an easy to search reference somewhere.

Read the entire manual, cover to cover, if you can. Create little demo projects to test your understanding of what you’ve read, and figure out how to do things. Read it again. And refer to it whenever you need to. There’s no substitute for reading and understanding the manual. I’ll still touch briefly on the major concepts here, for summary:

Surfaces

All drawing happens somewhere, and in GameMaker that somewhere is called a surface. Behind the scenes, a surface is simply a chunk of memory that is used to store graphics data. You can think of it as a 2D grid of pixels, stored in the program’s memory, and drawn to the screen only when called for. You can also think of it as virtual “scratch paper” where you do some work “backstage” and then bring it out to use in the game when needed.

The application has an Application Surface, and by default everything is drawn here. But you can create other surfaces, which you can work on, composing a drawing off-screen, until you are ready to draw it to the screen. As you might imagine, there are countless reasons why this is useful, and endless ways to make use of surfaces.

Surfaces are relatively easy to use, but are considered an intermediate level programmer’s tool in GameMaker, for a couple of reasons:

  1. Surfaces consume memory, and need to be disposed of when no longer needed.
  2. Surfaces are volatile, and can be destroyed without warning, so should not be assumed to exist. For example, if the player switches focus to a different application, or if the computer enters sleep or hibernation mode, or if the game is saved and resumed, surfaces that were in existence at the time the application was last running may have been cleaned up by the operating system, and will need to be re-created if they don’t exist.
  3. All drawing must happen in one of the Draw events. If you try to use draw functions in other events, it may or may not work correctly, and this will vary from computer to computer. I once made a game where I did some set-up in the Create Event of an object, where I created a surface, drew to it, and then created a sprite from the surface, and assigned the newly created sprite to the object. It worked fine on my computer, but when other players downloaded my game to try it out, it did unexpected things and the graphics were glitched. Fortunately, I figured out what the problem was, and fixed it by moving this sprite creation into the Draw Event. Once I did this, the game ran correctly on everyone’s computer.

Drawings done to surfaces can be run through a shader, as input, and thereby be processed by the shader. In short, a surface can be the input image data for a shader, and the output of the shader will be the processed version of that surface, transformed by the shader.

Blend Modes

For a long time, long before GMS introduced shaders, GameMaker has provided blend modes. Blend modes affect what happens when GameMaker draws graphics over existing graphics that were drawn previously. Normally, when you draw something, it covers the pixels that were there before. But, by changing blend modes, you can do other things than simply replacing the previous pixels with new pixels, blending the old and the new in different ways according to the mathematical rules of whatever blend mode you had selected.

To be honest, I’m not sure what useful purpose there is for every blend mode. It would be great if there were more tutorials showing useful applications for them, especially the obscure ones that I don’t see used much, if ever.

The most commonly useful blend modes, in my experience, are bm_normal and bm_add. Normal blending is the default drawing mode, and is what you use 99% of the time in most games. Additive blending creates vivid glowing effects, and is particularly lovely when used in conjunction with particle systems to create glowing systems of overlapping particles, especially when you are drawing translucent pixels (using alpha < 1).

Blend modes are also useful for creating clipping masks. For more info on that, there are some good tutorials already written on how to create a clipping mask using surfaces and blend modes.

Some of the first questions I had when Shaders were introduced were: What do we do with blend modes now that we have shaders? Do we still need them? Can we combine them with shaders, somehow? Or do shaders make blend modes obsolete?

Basically, as I understand it, the answer seems to be that blend modes were kind of a limited predecessor to shaders, and enabled GM users to achieve some basic drawing effects simply, without exposing GM users to all that highly technical stuff that shaders involve, that I mentioned above.

Anything you could do with blend modes, can be done with shaders instead, if you wanted to. That said, if all you need is the blend mode, they’re still there, still supported like always, and you can go ahead and use them. They’re still simpler to use, so why not.

One thing to be aware of, though, when using blend modes, every time you change blend mode in GameMaker, you create a new “batch” of drawing. The more batches, the longer GM will take to draw the game each step. Thus, many batches can slow drawing down tremendously. This is an area where you may need to focus on optimization. And if you’re that focused on performance, then it might be worth looking into a shader-based approach instead.

Once you’ve become sufficiently comfortable with shaders, you may not have as much need for using GameMaker’s drawing blend modes.

D3D functions

I have not used GML’s d3d functions, much, either, so my understanding is very limited. Basically, as I understand it, the d3d functions in GameMaker wrap Microsoft’s Direct3D drawing functions, and enable drawing with more sophistication than is possible with the basic GML draw functions such as draw_rectangle, draw_line, draw_ellipse, etc.

Despite the name, the Direct3D functions are useful for 2D drawing as well as for 3D.

This article will not cover using GML’s d3d functions, as we’re focusing on shaders. But as any graphics in your game can be used as input into a shader program, anything you draw using d3d functions can become input for a shader to process.

Particles

Particles are “cheap” (efficient) graphical effects that can be created without having to instantiate an object. They are efficient because they do not incur all the processing overhead that comes with a full-blown object. Huge numbers of particles can be generated at very little cost. These can be used for all sorts of effects, so long as the particles do not need to interact with instances in the game, such as triggering collisions. Typically, particles are used for things like dust clouds, smoke, fire, glowing “energy plasma”, haze, rain, snow, and so on to create additional atmosphere.

To use particles, you have to create a particle system. As with Surfaces, particle systems take memory, and need to be disposed of when no longer needed, in order to free up that memory. Full detail on how to set up and use particle systems is beyond the scope of this article.

Several external utilities have been developed by GameMaker users over the years to make designing, building, previewing, and testing particle systems easier, and these are highly recommended.

In conjunction with shaders, I don’t know that there is any direct interplay between particle graphic effects and shaders, but certainly a shader may be used to further process a region of the room where particles exist, to create more sophisticated effects.

Using Shaders in GameMaker Studio

Right, now that we’ve introduced the concept of what a shader is, and reviewed the other main graphics concepts in GMS, here’s where we get to the heart of how to use shaders in GameMaker.

A shader is a pair of shader-language programs, consisting of: a vertex shader, and a fragment shader. Vertex shaders deal with the edges of the drawn area, while fragment shaders deal with the insides.

Let’s say you want to use a shader program that has already been written, perhaps by someone else. All you need to do is use this code in your draw event:

shader_set(my_shader);
 //draw stuff
shader_reset();

So, it’s a lot like drawing to a Surface. With surfaces, first you set which surface you want to draw to, then you draw, then you reset so that drawing resumes to the application surface. With shaders, you set the shader you want to use, draw the stuff that you want to be transformed by the shader, then reset to normal drawing.

Everything drawn between setting the shader and re-setting back to non-shader drawing will be drawn through the shader program.

Easy enough, right? Well, there’s slightly more to it than that.

Uniforms

“Uniforms” is a strange term at first, and was where shaders started to seem strange to me. This is a term that comes from the shader language itself. The GameMaker manual talks about them in a way that assumes the reader is already familiar with the concept, and doesn’t go into a lot of detail explaining it to newbies.

In essence, “uniforms” are input variables that can optionally be passed into a shader that is designed to use input values. Once you understand what a uniform is, it’s not that difficult a concept. You can read more about them at these pages:

The gist of it is, when writing a shader program, when you declare a variable, you can declare it to be a uniform variable, which means that the variable can be accessed from outside the shader, thereby giving the program that calls the shader a way to change the shader’s behavior during execution. To do this, you can’t just refer to the uniform variable by name; you have to get the uniform variable’s memory handle, using shader_get_uniform(nameOfUniformVariable), and then change the value of the variable using shader_set_uniform_f(nameOfUniformVariable, value). Uniforms are actually constants within the shader’s execution scope, so once a value is passed into the shader from the outside and it is set as a uniform, it cannot be changed (the value could be copied to another variable, and that variable could then be modified, though.)

If you’re using a shader that has uniforms that you need to set, it’s done like this:

u_color1 = shader_get_uniform(my_shader, "f_Colour1");
u_color2 = shader_get_uniform(my_shader, "f_Colour2");

shader_set(my_shader);
shader_set_uniform_f(u_color1, 1, 1, 1);
shader_set_uniform_f(u_color2, 1, 0, 0);
//draw stuff
shader_reset();

There are actually a few uniform functions in GML:

Conclusion

That’s about all I know about shaders, for now.

As I get more familiar with using shaders, I’ll update this with more complicated examples, such as (possibly):

  • How to use multiple shaders on the same drawing (eg chaining the results of one shader’s transformation of some drawing into the input for a series of shaders).
  • Other stuff…

How to write shaders in GLSL, if I ever do it, will be a topic for its own article (or series of articles).

A tale of two GML scripts: code optimization through iterative development

Today I wanted to share two versions of a function that I wrote, in order to show how my iterative approach to software development works when I am doing code optimization to improve performance.

This example comes from my iMprOVE_WRAP asset. It’s a function that returns the shortest distance (taking into account the wrap capabilities of the calling object) between the calling instance and a target object.

The first implementation works, in that it correctly does what it’s supposed to do, but I never released it, because I wasn’t satisfied that it was good enough code to ship.

///iw_distance_to_object(target_obj, x1, y1, x2, y2, do_wrap_h, do_wrap_v,)

///@description Returns the distance_to_object from an improve_wrap object calling this function to another instance. 
///Compares all relevant points for the iw_object and returns the nearest distance, taking the wrap range into account.
///@param target_obj id of the target object to determine the distance to.
///@param x1 left x boundary of wrap range
///@param y1 top y boundary of wrap range
///@param x2 right x boundary of wrap range
///@param y2 bottom y boundary of wrap range
///@param do_wrap_h set whether the horizontal wrap is on (true) or off (false)
///@param do_wrap_v set whether the vertical wrap is on (true) or off (false)


//get the distance from the nine virtual positions
//return the shortest distance
var obj = argument[0];
var iw_distance, iw_distance_up, iw_distance_down, iw_distance_left, iw_distance_right, 
    iw_distance_up_left, iw_distance_up_right, iw_distance_down_left, iw_distance_down_right;
var tempx, tempy, shortest;
var x1, y1, x2, y2, range_width, range_height, do_wrap_h, do_wrap_v;

//keep track of original location of target object
tempx = x;
tempy = y;

//set up wrap range
x1 = min(argument[1], argument[3]);
y1 = min(argument[2], argument[4]);
x2 = max(argument[1], argument[3]);
y2 = max(argument[2], argument[4]);
range_width = x2 - x1;
range_height = y2 - y1;

do_wrap_h = argument[5];
do_wrap_v = argument[6];

//check distances
//check center
iw_distance = distance_to_object(obj);

if do_wrap_h && do_wrap_v //wrap vertical and horizontal
{
  //check corners
  x = tempx - range_width;
  y = tempx - range_height;
  iw_distance_up_left = distance_to_object(obj);
 
  y = tempx + range_height;
  iw_distance_down_left = distance_to_object(obj);
 
  x = tempx + range_width;
  iw_distance_down_right = distance_to_object(obj);
 
  y = tempy - range_height;
  iw_distance_up_right = distance_to_object(obj);

  //check left and right
  y = tempy;
  x = tempx - range_width;
  iw_distance_left = distance_to_object(obj);
  x = tempx + range_width;
  iw_distance_right = distance_to_object(obj);

  //check up and down
  x = tempx;
  y = tempy - range_height;
  iw_distance_up = distance_to_object(obj);
  y = tempy + range_height;
  iw_distance_down = distance_to_object(obj);
 
  shortest = min(iw_distance, iw_distance_up, iw_distance_down, iw_distance_left, iw_distance_right, 
                iw_distance_up_left, iw_distance_up_right, iw_distance_down_left, iw_distance_down_right);
}
if do_wrap_h && !do_wrap_v //do_wrap_h
{
  //check left and right
  x = tempx - range_width;
  iw_distance_left = distance_to_object(obj);
  x = tempx + range_width;
  iw_distance_right = distance_to_object(obj);

  shortest = min(iw_distance, iw_distance_left, iw_distance_right);
}

if do_wrap_v && !do_wrap_h //do_wrap_v
{
  //check up and down
  y = tempy - range_height;
  iw_distance_up = distance_to_object(obj);
  y = tempy + range_height;
  iw_distance_down = distance_to_object(obj);

  shortest = min(iw_distance, iw_distance_up, iw_distance_down);
}
if !do_wrap_h && !do_wrap_v
{
  shortest = iw_distance;
}

//return calling instance to original location
x = tempx;
y = tempy;

return shortest;

Let’s take a moment to appreciate this function as it’s written. It’s well-structured, documented, and expressive. First we declare a bunch of variables, then we do stuff with the variables, then we get our answer and return it. And this gives a correct result…

So what’s wrong with the above? It’s an inefficient approach, which checks each virtual position of the wrapping object. If the calling instance wraps vertically and horizontally, it has to temporarily move the calling instance 9 times and check the distance from each of 9 virtual positions, then return it back to its original position, only to return the shortest of those 9 virtual positions.

There’s also a lot of code duplication.

Still, it’s not horrible code. But it’s up to 9x slower than the distance_to_object() function it’s based on, if you’re wrapping in both directions, which will probably be common. I didn’t think that was good enough.

Rather than check each virtual location to see which is the shortest distance, we just need to know whether the horizontal and vertical distances are more than half of the width and height of the wrap region. If they are, then it’s shorter to go around the wrap. To know this, you simply take the x and y values of the two positions, subtract one from the other, and compare to the size of the wrap range. Once you know which virtual position is the closest one, you can temporarily place the calling instance there, and use distance_to_object() to get that distance. Put the calling instance back where it was, and then return the distance.

I realized as well that depending on whether the calling object wraps in both directions, you may not need to check for a wrap shortcut in the horizontal or vertical. So we can potentially avoid doing some or all of the checks depending on whether the do_wrap_h and do_wrap_v arguments are true or false. As well, this means we can avoid declaring certain variables if they’re not needed, which conserves both execution time as well as RAM.

I usually create local script variables in a var declaration, and assign the arguments to them so the code will be more readable, but I wanted to avoid doing that so that this function could be as lean and fast as possible. This might be an unnecessary optimization, but that’s hard to predict since I have no way of knowing ahead of time how this function might be used in a future project. In a project with many wrapping instances, it could very well be called many times per step, and every optimization could be critical. Since the script is intended to be included as a function in an extension, once I have it working properly it shouldn’t be opened for future maintenance, so making the script readable is not as important. So I opted to remove the local variable declarations as much as possible and just use the argument[] variables directly.

Also, to ensure that the wrap range is defined properly, in the non-optimized version of this function, I declare x1, y1, x2, y2 and assign their values using min() and max() so that (x1, y1) is always the top left corner, and (x2, y2) is always the bottom right corner of the wrap range. Technically for this function, we don’t care precisely where the wrap range is, only what the width and height of the wrap range are. That being the case, I can further optimize what I have here, and rather than use min and max, I can just take the absolute value of the difference of these two values.

It turns out that the process I went through to optimize this function is pretty interesting, if you care about optimizing. So I’ll go into greater detail at the end of this article about the approach I took to get there. But for now, let’s skip ahead and look at the finished, optimized function. Here it is, re-implemented, this time doing only the minimum amount of work needed:

///iw_distance_to_object(obj, x1, y1, x2, y2, do_wrap_h, do_wrap_v)

///@description iw_distance_to_object returns the shortest distance in room pixels between two objects in the wrap range, 
///taking into account the horizontal and/or vertical wrap properites of the calling object.
///@param obj the id of the target object
///@param x1 left x boundary of wrap range
///@param y1 top y boundary of wrap range
///@param x2 right x boundary of wrap range
///@param y2 bottom y boundary of wrap range
///@param do_wrap_h set whether the horizontal wrap is on (true) or off (false)
///@param do_wrap_v set whether the vertical wrap is on (true) or off (false)


if !(argument[5] || argument[6]) //not wrapping actually
{
 return distance_to_object(argument[0]);
}
else
{
 //We're going to figure out which virtual position is the nearest to measure from
 //To do that, we have to compare the h-distance and v-distance of the calling instance and the target position
 //If this distance is <half the range size, then the original position of the calling instance is closest
 //Otherwise we have to use one of the virtual positions
 //Then we're going to temporarily put the calling instance in that location, get the distance, and put it back 
 
 //arguments
 var tempx = x, tempy = y;
 
 if argument[5] //do_wrap_h
 {
   var range_width = abs(argument[3] - argument[1]);
   if abs(x - argument[0].x) > (range_width * 0.5)
   {
     x -= sign(x - argument[0].x) * range_width; 
   }
 }
 
 if argument[6] //do_wrap_v
 {
   var range_height = abs(argument[4] - argument[2]);
   if abs(y - argument[0].y) > (range_height * 0.5)
   {
     y -= sign(y - argument[0].y) * range_height;
   }
 }
 
 var d = distance_to_object(argument[0]);
 
 //return calling instance to where it was
 x = tempx;
 y = tempy;
 
 return d;
}

We don’t need to measure all nine distances to know which is the shortest; we can tell by comparing the direct distance to the size of the wrap zone — if it’s less than half as big as the wrap zone, the direct distance is the shortest. If not, then we need to wrap. We can check the x and y axes separately, and if both are called for then we can just combine them.

The second function should be much faster to execute, and uses less RAM. How much faster? Well, let’s do a test project using my Simple Performance Test and compare.

Download the iMprOVE_WRAP distance_to_object test project

It turns out that the improved code runs about 50% faster than the old code! That’s a measurable and worthwhile improvement. Although, that said, the old function ran well enough that I could have released it, and likely it would not have been a problem for many uses, particularly in Windows YYC builds.

Appendix: Optimization through Iteration

(more…)

GameMaker Tutorial: Instance Pooling for performance optimization

Instance pooling is a design pattern which can potentially help performance in games where you are creating and destroying a lot of instances.

If your program is spawning and destroying objects very frequently, calling the Create and Destroy Events many times per step, it’s potentially a lot of extra processing. Creating instances and destroying others constantly seems wasteful. Why destroy the instances that need to be destroyed when instead you can re-use them, and avoid having to call the Create event on a New instance every time you need one?

The Code

You can download my demo code here:

The GMS2 demo is an import of the 1.4 demo, cleaned up to remove the Compatibility scripts.

Looking at the project code, you will see that I have used inheritance to make the Control and Instance Pool test implementations as close to identical as possible. I have included telemetry code, which tracks the FPS of the game while it runs, so that performance is quantifiable. In the GMS1.4 version of the project, all of the telemetry code is neatly separated from the demo code into its own Execute Code action. This makes it easy to modify the project for your own use, and get rid of the telemetry code entirely if you don’t need to quantify runtime performance, and only want the code that actually implements the Instance Pool pattern.

How it works

The basic concept of the Instance Pool pattern is simple. The goal is to minimize the amount of times we create new instances of some object in large numbers during the game. A good candidate for objects to use Instance Pooling with would be bullets, bonuses, and enemies. Instance Pooling is particularly beneficial when the object in the pool is somewhat “heavy” — that is when the Create or Destroy events cause a lot of processing to happen.

The way we achieve this goal is by re-using already-existing instances of the object. This is done by deactivating the instance rather than destroying it. We add the id of all deactivated instances to our Pool. Then, when a new instance is needed, we first check the pool to see if an already-created but inactive instance exists, and if so, we remove it from the pool, activate it, and re-use it.

The most efficient way to create and manage our pool is with a stack. Stacks are elementary data structures in computer science. Imagine a stack of pancakes. The stack gets bigger as you add more pancakes to it. If someone orders a pancake, you take the top one off of the stack, and give it to them.

This is what’s known as Last In, First Out, or LIFO data access. This happens to be just what we need. The stack gives us an easy way to keep track of the id of all of our deactivated instances, and when we need to activate one, we just pop it off the top of the stack. This is very simple to do, and therefore very fast. In GameMaker, stacks are created by ds_stack functions. If you’ve never used them before, take a moment to read up on them. It will help you understand how the demo works.

The code at the heart of this is quite simple. It looks like this:

//First check the pool to see if it has any deactivated instances in it that we can use
 if ds_stack_empty(pool)
 {
 //If not, we need to create a new instance. No performance gain.
 instance_create(x,y,oInstancePoolBullet);
 }
 else
 {
 //If the pool has an instance we can use, take it out and activate it.
 var bullet = ds_stack_pop(pool);
 instance_activate_object(bullet);

 //Reset the state of the instance. 
 //**If** this is cheaper than a new instance, we gain performance.
 bullet.x = x;
 bullet.y = y;
 bullet.direction = direction + random_range(-20,20);
 bullet.alarm[0] = bullet.TTL;
 }

There’s only a little bit of other code that you need. You need to create the ds_stack, most likely this is best done in the Create Event, using ds_stack_create(). And when the pool is no longer needed, you need to destroy the ds_stack using ds_stack_destroy(), most likely in the Destroy Event.

Of course, we also need to push instances to the stack when they are no longer needed. To do that, we do this whenever we would ordinarily destroy the instance:

ds_stack_push(oInstancePoolPlayer.pool, id);
instance_deactivate_object(id);

So, don’t destroy instances that you want to pool; deactivate them instead. With our bullet demo, I do this by giving bullets a “time to live” and then setting an timer. When the alarm goes off, the instance’s id is added to the stack, and the instance is deactivated. Then it just waits for the game to need it. In a full game, you would need to look at other occasions where you need to deactivate the bullet, such as when it goes outside the room, off the screen, or when it hits an object.

That’s basically it. But you may need to think about some additional concerns, which I will cover in the Findings section of this tutorial.

Running The Demo

Open the project with GameMaker Studio, compile, and run.

The Demo consists of an Instance Pool demo and a Create-Destroy demo for comparison.

Press the Space bar to spawn bullets. Press Tab to switch from one demo to the other.

The FPS is displayed at the top-left of the screen. The first number is the minimum fps, the middle is the average fps over the last 30 steps, and the last number is the maximum fps. The minimum and maximum fps reset once per second. The average is a rolling average over the last second.

In the Instance Pool demo room, hold the space bar down until the first bullets to spawn reach the end of their life. At this point, the instance pool is filled, and no more instances will spawn; instead, deactivated instances will be re-used. At this point, you should notice the FPS dramatically shoots up and stays consistent.

Findings

To my surprise, I did not find that there was much benefit to creating an Instance Pool for bullets. Create and Destroy is about as fast as Instance Pooling with simple bullet objects in GameMaker. I expect the reason for this is that the GameMaker runtime engine is not particularly fast, but even when I did a YYC build, I still saw no real advantage to using an Instance Pool, at least in terms of fps.

Over a long game session, it may be that there is a reduction in memory fragmentation since we are updating values in RAM that has already been allocated, rather than rapidly allocating/de-allocating memory when we create new instances and destroy them constantly. But I haven’t tested that, so it’s merely speculation for now. Update: This benefit of reducing memory fragmentation is confirmed by Mike Dailly of YoYoGames.

In order to show a benefit to Instance Pooling, I had to weigh down the Create Event for my bullets. To do this, I ran a simple repeat loop to increment a variable. This is obviously inefficient and pretty pointless, but it serves the purpose of simulating a complicated object with an init script that takes some time to run. If that init script needs to be run only once, and not every time the instance is re-used, then there is a benefit and using the Instance Pool pattern will help.

When does it make sense to use the Instance Pool pattern? When there is a performance issue, and the Create or Destroy Events are more expensive than instance_activate_object() and instance_deactivate_object().

Setting up and managing the instance pool is pretty simple, but it does take some work, and incurs some overhead. It’s not worth it to incur this overhead unless there’s a tangible benefit in the form of noticeably improved performance.

Run the code profiler, and see where your code is spending the most time. If it’s heavy on Create and Destroy events, an instance pool might be just what the doctor ordered. Otherwise, you may want to look elsewhere for your low framerate fix.

Additional Considerations

As I mentioned, there are a few other considerations that you should think about when implementing an Instance Pool, which I will discuss here.

Should we Prime the pool?

In my demo, we only create new instances when there are none in the stack. This means that until we’ve deactivated our first instance, the stack is empty, and there is no performance gained by having it.

In fact, since we’re checking the stack before we create each new instance, there’s actually an infinitesimal hit to performance. When you run the Instance Pool room, we see pretty much the same fps performance as we did in the Create-Destroy room, until the first bullets start to be recycled. Only then do we see fps shoot up.

Well, what if we want the performance to be high from the very first bullet? We can do that, by priming the stack, by creating a bunch of bullets, and then immediately deactivating them and pop their id’s onto the stack.

We could create a special object that we might call oPoolPrimer, which lives for several steps, creates the instances we need and deactivates them, adds them to the Instance Pool stack, and then destroys itself when its work is done.

The best time to do this is when the performance hit won’t be noticed, such as when the game is in a menu screen. Alternately, we can create the instances gradually, over a longer time than would introduce a noticeable performance penalty.

To be effective, you will need to have a good way of calculating maximum the number of instances you need to have active in your game at any given time. Prime your pool with that many instances. That way, even when you have all of them active, you aren’t creating new ones, and your fps will stay high.

Trim the pool?

One of the downsides of the Instance Pool is that all those deactivated instances take up resources. Even though the CPU may not be spending as much time with those instances, they do incur some processing overhead to manage even when disabled, and as well they use some RAM.

Depending on your game, you might have a moment when you need a huge number of instances active, but in other parts of the game the action isn’t as intense, and you won’t need so many. For example, in my demo, I spawn 100 bullets per step, for 20 steps, resulting in some 2000 instances max if you hold the space bar down the entire time. But if you don’t need to shoot all the time, all those disabled bullets end up in the stack. Do you really need 2000 disabled instances? If there isn’t going to be as much shooting going on, you might not. We can free up resources by trimming the stack every so often.

One way to do this would be to set a recurring alarm so that every few seconds, the stack is trimmed if it goes over a certain size.

///Alarm0 Event:
while ds_stack_size(pool) > trim_limit
{
 //remove the top instance from the stack and destroy it
 with ds_stack_pop(pool) {instance_destroy();}
}
alarm[0] = reset;

This will keep the stack small when it doesn’t need to be so big.

Delete the pool?

If you delete the stack, you should realize that any disabled instances that we were tracking in the stack still exist. They will continue to do so until the game ends, or you change rooms. If you don’t change rooms right away for some reason, you may want to run through the stack before you destroy it, popping all the instances out of them so that they can be destroyed as well. Otherwise, those inactive instances will continue to take up resources.

while !ds_stack_empty(pool)
{
 //remove the top instance from the stack and destroy it
 with ds_stack_pop(pool) {instance_destroy();}
}
ds_stack_destroy(pool);

 

Benefits in network multiplayer games

This comes from GMC Forums user JuJu: There’s a nice implicit benefit of instance pooling: It makes handling multiplayer netcode for complicated scenes easier if you can refer to instances by a common index across all machines.

GMS2 Impressions: Tilesets and AutoTiling

One of the best new features in GameMaker Studio 2 is the improved tile system.

I never used tiles much in GMS1, because they were such a pain to work with, and did so little. In GMS1, tiles were a type of background resource. In the GMS1 room editor, you had to select your tiles manually, then place them one click at a time, which was very tedious. GMS users developed complicated auto-tiling scripts that would select the correct tile and place it in the room at runtime. This solution worked well, but was complicated to understand, set up, or modify. GMS1 tiles did not support animation, so if you wanted animated backgrounds, you either had to use sprites, or else come up with some sophisticated tile-swapping script that would programmatically animate your background tiles.

If you wanted your tiles to represent some kind of interactive object in the game, you had to also place an invisible object behind the tile, and program it to do whatever behaviors you needed. To me, there wasn’t much point in using tiles when I could just assign a sprite to the object, and use the object directly. If you did work with tiles in GMS1, then you may have to unlearn or relearn a few things before you feel comfortable with the new system.

I’m happy to say that in GMS2 the situation is much better. GMS2 tiles support animation and auto tiling. You can draw tiles in the room by the mouse without having to click each and every time you want to place a tile. This makes working with them much easier than it used to be.

However, there is still a lot of learning to do in order to develop the understanding necessary to set up tilesets and get the full use of them in your projects.

It took me an evening to figure out, about 4-6 hours, which isn’t bad. But after I had figured it out to the point where I have auto tile working, I realized that I could save others a lot of frustration by going a bit further to explain it.

Getting into GMS2 Tiles

First, the help manual articles on the Tileset Editor is essential reading. There are several articles which you should read first. And maybe a few YouTube videos are also helpful, to see the process of setting up a tileset for use within your project.

It’s actually pretty easy to use after you’ve gone through the process once so you understand it, but until you’ve completed your first working tileset, you’ll probably have a lot of questions and uncertainty about how it all works and what you’re supposed to do.

This article will guide you through that first time, and explain things so that they are easier to understand, and you’ll have an easier time of it than I did.

Before getting into that, there are a few constraints that you need to be aware of when working with tiles.

  1. The tile grid size must be a power of 2. So, for the most part, 8×8, 16×16, 32×32, or 64×64 tiles will be the sizes to work with.
  2. Any tile-based animations must have a number of frames that is a power of 2: 2, 4, 8, 16, etc.
  3. Tile positions in a room are constrained to a grid in GMS2. You can no longer position them at an arbitrary position in the room; they must snap to a grid the size of the tile.
  4. However, that entire grid may be offset, using the X Offset and Y Offset properties.
  5. Tiles are placed in layers, and you can use as many Tile Layers as you like in the Room Editor.

Now that we’ve covered that, let’s look at the Tileset setup and usage workflow.

GMS2 Tileset Workflow

First, let’s take a general overview of the entire workflow, before we dive deeper into each step:

Tileset setup

Before you can use a tileset to decorate a room, you have to set up a Tileset resource. A Tileset resource is a resource that depends on a Sprite resource, and defines how the image in the Sprite is sliced up to create a set of tiles.

  1. Create a sprite that will hold the image data for your tileset.
  2. Create a tileset asset.
  3. Define the tileset.
    1. Add the sprite from Step 1 to the tileset.
    2. Set tile size to split up the image into tiles.
    3. (Optional): Create any brushes, animations, and auto tile sets that are needed.
  4. Create additional tilesets, as needed.

Tileset usage:

This is where you put your tiles to work in the game. It’s all about creating and managing Tile Layers in your rooms, using the Room Editor.

  1. Add a tile layer to a room
  2. Select a tileset to use in the layer
  3. Add tiles to the tile layer.
  4. Add additional tile layers to the room, as needed.

Now that we’ve covered the workflow of Tile setup and usage at a high level, let’s go back and look at each step in depth.

Tileset Setup

Create a sprite that will hold the image data for your tileset

The first thing you need to do is create a Sprite resource, and add an image to it containing your tiles.

If you’re drawing this yourself, you’ll need to learn how to lay out this image. The first thing you’ll need to understand is that your tiles need to conform to a grid. You should set up the grid in the Image Editor to the size you’ll need for your tiles. I found that using an Image Editor grid that is half of what I want my actual tile size to be works well, so for a tile image that I wanted to draw that would have 32x32px tiles in it, I set the grid size in the Image Editor to 16×16. Then I drew out my tiles, using chunks that were 2×2 grid cells.

An important thing to realize in drawing your tiles is that your tile images should include some solid pixels as well as negative space surrounding the solid part of the tile. This is difficult to understand, especially at first, and it takes some getting used to the idea. To explain this properly, I need to illustrate.

tile_grid

As you can see here, I have drawn a brown rectangle, representing a solid object in the game room, and overlaid a green grid on top of it, showing how the tile borders should look if they’re done properly. Noticed that each tile (except for the center ones, which are completely solid) shows a certain amount of solid space and some white space.

I think a lot of people probably mistakenly think that their grid of tiles should look like this:

tile grid wrong

I know I did, at first. It’s hard to understand why tiles don’t work the second way — it seems a lot more obvious to position them that way, doesn’t it? After all, it takes fewer tiles, and there’s no overlapping into the negative space surrounding the solid object. If you’re just thinking about a simple rectangular platform or wall like this, it’s easy to think that it should simply be a 2×4 rectangle of solid brown tiles, all the same. The thing is, if you go back to the first illustration, you can see that in that illustration, we have many different types of tiles, representing edges, corners, and solid areas, working together to create the same rectangular platform, and since they’re not all the same tile, you can re-combine them in many different arrangements, to create other shapes.

Since the point of making the tile set is to enable you to create all the different types of edges and corners, you want to make sure that the sprite your tiles are drawn in is laid out in such a fashion.

We really need to create a ring so we can have inner and outer corners represented in our tile. We also need to have a tile representing a completely open space. By convention, GMS2 auto tile sets reserve the top left tile grid for this empty tile. Here’s a better image that shows all the different corner and edges that we’ll need for a complete tile set:

tile template

With this arrangement, we are able to create almost any arrangement of blocks, but we still have a few more tiles to create. We actually have a few duplicates in this tile set, which I’ll color code in the next illustration, as well as number the unique tiles.

tiles-14

As you can see, we have 14 unique tiles in this image, and a few duplicates. There are actually two more tiles that we’ll need to create a universal 16-tile auto tile set. They are:

tiles 15 and 16

We can consolidate space in our earlier image by eliminating some of the redundant tiles and replacing them with the ones we needed, like so:

tiles-16

Really, these tiles could be arranged in any ordering; this is just an example of one such arrangement.

There’s also a 47-tile auto tile but I think now that we’ve walked through the 16-tile auto tile set creation, you should be able to figure out the 47-tile version on your own. The ideas are the same, it’s just more work.

But just to make things convenient, here are two templates that I’ve created for 16×16 and 47×47 auto tiles, matching the order that the GMS2 Tile Set editor uses for its template:

16-tile tileset template for GMS2

16-tile tileset template for GMS2

47-tile tileset template for GMS2

47-tile tileset template for GMS2

You can right-click the images above, save, and use these for laying out your own tiles. No need to ask permission or give credit.

If you need 32×32 sized tiles, or larger, just scale the image up to whatever you need. Then import the image into the GMS2 Sprite Editor, set the grid to the size you need, and draw over the template in a new layer until you’ve built up your tiles!

I will point out here, that this sheet that we’ve created above just gives us a starting point to create a single auto-tile set. Most games will likely need several tilesets, for different areas of the game. Auto-tiling is best for your basic terrain, such as walls, floors, and platforms.

We could also choose to include numerous additional tiles in one sprite image if we desire, for decorative things that do not make sense to do auto-tiling with, or create additional tiles to represent terrain features in the game such tables and chairs, or other furniture, or trees, bushes, you name it. Or we could store each type of terrain, decorative elements, etc. in its own tileset resource.

We could also duplicate this 16-tile layout multiple times, and include in a variety of different terrain types, or different colors, all in a single large tilesheet. Or we could have multiple tile sheets. But be cautious about making the sheet too large. You’ll want to read the Texture Groups section of the manual to understand the limits of how large your sheets can be.

One last thing: If you wanted to create an animated auto-tiling tileset, you would need to create additional copies of our 16-tile auto tile layout, and draw each one as a different frame of animation. We’ll explain how to do this in the section on creating tile animations.

Create a tileset asset

Now that we have a sprite holding the image for our tile set, it’s time to create the tile set asset. To do this, right-click on the Tile Sets section of the resource tree, and select Create. You can name the new Tileset something meaningful, such as grassland, or ocean, or city, or indoors, or whatever suits your game.

Define the tileset

The Tileset editor looks like this:

GMS2 Tileset editorThe first thing to do is to add the sprite from Step 1 to the tileset. Click on Select Sprite, and select the sprite. Next, set tile size to split up the image, by entering the information in the Tile Properties fields at the right, as appropriate. The sprite image will appear sliced up by a grid as you change these values. At this point, we could use our newly created Tileset right away, by going to the Room editor, adding a Tile Layer, and drawing in some Tiles from our newly created Tileset.

(Optional): Create any brushes, animations, and auto tile sets that are needed

Once the grid looks how you want it, we’re ready to create any Brushes, Animations, and/or Auto Tiling sets that are needed. These are very useful, and powerful, new features that have been added to GMS2’s tiles. Not every Tileset needs Brushes, Animations, or Auto Tiling to be defined for it, but when you do use these, especially Auto Tiling, it will make creating your rooms much easier and faster.

This is where it really starts to get good.

Brushes

A brush is a selection of tiles, grouped together and added to your tile layer as one. Let’s say you have something in your tile that takes up more than one tile. This could be a large terrain feature, such as a building, or a mountain, or a tree. Without using brushes, every time you wanted to plant one of these multi-tile features in your room, you’d need to select each tile one at a time, place it in your Tile Layer, in the correct arrangement… this is tedious work and easy to screw up. So Tile Brushes make this easier by collecting the related tiles together, so that they can be added to the Tile Layer with just a single click to place the entire Brush.

You can use Brushes not just to place multi-tile graphics, but to place arrangements of platforms. Say you have a particular jumping puzzle that you want to repeat several times in a level; you can create a Brush with the tiles spaced out in just the way you want them, then place them quickly and easily into your Tile Layer.

Animation

Setting up Animation Tiles is pretty easy. Simply add a new Animation, specify the number of frames (which must be a power of 2), and then add the tiles that make up the animation one at a time until you’ve filled out the animation.

It’s worth noting that you don’t have to use Tilesets to do animation. You can place any sprite resource into a room directly, without the need to place an instance of some object to draw the sprite for you. These can be added to asset layers or background layers. Background layers can tile or stretch or both, and can move. So consider whether you need to do your animations in tiles or if you can do them more easily another way.

Auto Tile

Setting up an auto tile set is pretty easy too, although at first it seems complicated. Taking the sprite that we created, above, we have all the tiles we need to create a 16-tile auto tile set. GMS2 also supports a 47-tile system, but it is much the same to set up.

Create a new Auto Tile set. The auto tile set will present a template which you have to fill in with tiles from your tileset sprite. Simply go through the template by clicking on each tile in the template, then click on a tile from your tileset sprite to connect it to the template. The currently selected tile in the template is red, and as you go through your tileset adding tiles to the auto tile template, it will fill in the tile you selected, then advance to the next tile in the template automatically.

GMS2 auto tile editorThe key to understanding the auto tile template is that the light grey parts of the template are meant to represent the solid parts of your tile, and the dark grey parts are meant to represent the empty space. If you didn’t know this up front, it’s very difficult to read the template correctly, and this was one of the most confusing parts of figuring out the auto tile editor.

Each of auto tiles (remember, there can be more than one in a tileset resource) is called an auto tile library. The image above shows two auto tile libraries about to be created; a 16-tile library, and a 47-tile library, just to show what they both look like.

It’s also important to understand the buttons to the right of the auto tile templates, which look a bit like a yinyang. These control how the tileset treats the borders of the room. Outside the edges of the room, the tileset must make an assumption: either the tiles outside the room count as empty, or as filled. This influences the auto tile system to select the appropriate tile at the room edge, and will result in an edge border around the room if the outside is treated as empty.

Once you’re done setting up the Tile Set resource, when you go to the Room Editor, in the Tile Layer editor, you’ll see a section in your tile palette called Libraries. Here, you can select Brushes, Animations, and Auto Tile sets to draw, rather than selecting individual Tiles from your Tile Set.

Pro Tip: An auto tile library will not work until and unless every tile in the template has been assigned. If you try laying out auto tiles in a tile layer and they just won’t draw, no matter what you do, go back and look at the template. Somewhere in there, some part of the template has not been assigned to a valid tile in your tileset.

The auto-tiling section in the manual illustrates this pretty well, with some nice animations showing how it works.

Animated Auto Tile sets

To create an animated Auto Tile set, simply make sure that each tile in your Auto Tile set is the first tile in an Animation set. In the room editor, the tiles will not animate, but as long as you place animated tiles in the editor using the first image in the animation, they will animate at runtime.

Re-Auto Tiling (Auto Tiling at runtime)

What if your room changes once the game starts? For example, if you have destructible terrain, and a piece of a platform gets destroyed, will the tiles automatically adjust accordingly? Unfortunately, no. Not yet; Dynamically re-auto-tiling at runtime is not supported by GMS2 at present, but it is a planned feature according to YYG lead programmer Mike Dailly, albeit with no release date announced yet.

This means that, at least for now, your auto-tiled setup will not automatically update the tiles if something changes during the game, for example if a new platform is created, or an existing one is destroyed, the tiles in the adjacent region will not update. This can cause things to look weird.

Presently the only way to handle this would be through a custom coded solution to evaluate the neighbors and determine an updated arrangement of tiles. This is pretty much the old system from GMS1, when auto-tiling was done at runtime.

There are scripts published on the GMC Forums and available for purchase in the Marketplace that will do auto-tiling for you, and YouTube videos describing how they work. These will need to be updated in order to be compatible with GMS2. At this time I haven’t evaluated these solutions, so I won’t be making a recommendation for any here. Hopefully YYG will provide a built-in solution in the form of GML functions, and there won’t be a need to invest time into developing custom solutions.

Create additional tilesets, as needed.

Your project can have as many tilesets as needed. Create as many as you like, to allow you to create as many different environments as you need for your game. It’s probably best to start simple and just create one at first, and then once you’re happy with it and satisfied that you know how to use the tile system, create additional Tilesets.

You can use multiple Tilesets in the same room, and in different layers, overlapping them. This is how you can develop very nice looking rooms.

Can a tile layer move/scroll?

Short answer: Yes. The functions tilemap_x() and tilemap_y() allow you to move a tile layer around the room. For complete details of all the things you can do with tilemaps, consult the manual.

The individual tiles in the tile layer have to align to their grid. So you can’t offset individual tiles, and make them move. But you can move the entire tilemap. If need be, you could put a few tiles in a layer that moves, and use this to create moving terrain features. For things like crumbling tiles, or tiles that break loose and drop one at a time when the player stands on them, it’s better to handle these with objects rather than tiles; of course, you can just use a sprite that looks the same as the tileset that you’re using, so everything blends together.

Tile Collisions

GMS2 can handle collisions between instances and tiles directly, without the need to use instances of hidden collision object behind the tiles. This is very handy, since you no longer need to lay out a bunch of instances in a room, then tile over them, and as well it offers greater performance, because there’s much less overhead involved with tiles than there is with instances.

Tile Collisions are meant for solid, stationary objects, such as platforms in a side-scrolling game, or walls in a top-down game, not for handling all possible collisions in your game. You will still want to use normal collision events for handling collisions between different objects in the game.

I mention them here so you’re aware of it, but rather than make this article even longer, I recommend you watch the tutorial video by GMWolf, which explains one approach for how to make a tilemap collision system in GMS2. His approach is to create a separate, invisible tile layer for the collision tilemap, which separates collisions from the decorative tile layer, which allows you to have decorative tiles which have rough edge texture, for surfaces like tall grass or uneven rock. The collision checking is performed by the objects in your game, which check to see if their sprite’s collision mask overlaps the tiles in the collision map.

It’s a very good approach, but it is just one way to do it. In GMWolf’s demo, a player object is prevented from entering into the region covered by the collision map. But there may be other types of collision checking, for example to determine if the player has entered a region that does damage, or is overlapping a ladder tile. Each of these situations can be handled by some variation of this basic approach, using additional collision tilemaps for different types of collisions. For example, you could have a collision tilemap for solid platforms, another collision tilemap for ladders (which triggers your character’s climbing behavior), one for water (which triggers water physics), one for slippery platforms, one for danger zones, etc., as many as needed. You can even use a collision tilemap to trigger events, such as to spawn or activate enemies when the player reaches a certain region of the game. There are many possibilities, so use your imagination.

Isometric and Hexagon tiling?

Because of GMS2’s requirement that tiles align to grid, you can’t lay out isometric or hexagonal tiles in a single tile layer. You’ll need to use a two layer approach, with the second layer offset horizontally and vertically, so that the two layers blend together.

This approach has its downsides. Having to switch back and forth between the two layers when laying them out in the room editor is a pain. And checking both layers for collisions doubles the amount of work the game needs to do at runtime for handling tile-based collisions.

I hope that something is done about these problems, I would like to see an “isometric grid” checkbox in the layer editor that allows aligning to a half-sized grid, or perhaps a new tile layer type for isometric tiles. But for now a two layer solution seems to be the best approach.

Update: YYG lead developer Mike Dailly recommends that we refer to the Isometric demo in GMS1.x for their recommended approach to do isometric games, and adapt that for GMS2 as necessary. (Hopefully a GMS2 Isometric demo will be happening eventually).

GML move functions and Tiles

If you use the GML functions

move_bounce_all() move_bounce_solid()

move_contact_all() move_contact_solid()

move_outside_all() move_outside_solid()

these work with the collision mask of objects, not tiles. So they will not be helpful to you if you’re implementing a tile-based collision system.

However, you can write your own version of these functions to work with tiles; to do so you just need to understand how the built-in functions work, and how to detect collisions with tiles.

The function move_bounce simply reverses the hspeed and vspeed of the bouncing object:

So, first determine whether the tile collision is horizontal or vertical, then use:

hspeed *= -1;
vspeed *= -1;

to reverse the appropriate speed variable.

If the bbox_left or bbox_right is in collision, set hspeed *= -1. If the bbox_top or bbox_bottom is in collision, set vspeed *= -1.

The move_bounce functions also take a boolean argument to turn on “advanced” collisions, which use the collision mask to do precise checking. These are slower to calculate, and the manual recommends not to use advanced unless it’s necessary, but they otherwise work the same. If you wanted to, you could come up with a tile collision check that uses the sprite’s collision mask to check for collisions with tiles, and use that.

The move_contact and move_outside functions work by using a while loop to check for collisions with the calling object, moving it one pixel at a time until the while condition is satisfied. This is easy enough to implement in a tile-based system as well.

Further Reading/Videos

Fun enum ideas for game development

Most video games have a counting, ranking, or level system of some sort. It’s often good to have a thematic flavor to your counting systems. This way, rather than calling your level progression by boring old regular numbers, you can give each level number a meaningful, or flavorful, name. This can add character or meaning to your game world, or it can be used to help disguise the underlying math, resulting in a game where the underlying mechanics are masked away from the player, leading to a more mysterious experience where they need to experiment and discover. What’s cooler: a “level 3 sword?” Or “the sword of autumn?” What’s more powerful: the knight sword or the rook sword?

To that end, I thought I’d demonstrate a few example enums that you can use to spice up your game design.

ENUMerate all the things!

Alphabet {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z}

Greek Alphabet {Alpha, Beta, Gamma, Delta, Epsilon, Zeta, Eta, Theta, Iota, Kappa, Iota, Kappa, Lambda, Mu, Nu, Xi, Omicron, Pi, Rho, Sigma, Tau, Upsilon, Phi, Chi, Psi, Omega}

Military Phonetic Alphabet {Alpha, Beta, Charlie, Delta, Echo, Foxtrot, Golf, Hotel, India, Juliett, Kilo, Lima, Mike, November, Oscar, Papa, Quebec, Romeo, Sierra, Tango, Uniform, Victor, Whiskey, Xray, Yankee, Zulu}

Army (simplified) {Private, Specialist, Corporal, Sergeant, Officer, Lieutenant, Captain, Major, Colonel, General}

Navy (simplified) {Seaman, Petty Officer, Ensign, Lieutenant, Commander, Captain, Admiral}

Chess {Pawn, Knight, Bishop, Rook, Queen, King}

Rainbow {Red, Orange, Yellow, Green, Blue, Indigo, Violet}

Elements {Earth, Air, Fire, Water}

CardRank {Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace, Joker}

CardSuit {Clubs, Diamonds, Hearts, Spades}

Zodiac {Aquarius, Pisces, Aries, Taurus, Gemini, Cancer, Leo, Virgo, Libra, Scorpio, Sagittarius, Capricorn}

Seasons {Spring, Summer, Autumn, Winter}

Months {January, February, March, April, May, June, July, August, September, October, November, December}

Weekdays {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}

Lunar Cycle {New, WaxingCrescent, FirstQuarter, WaxingGibbous, Full, WaningGibbous, ThirdQuarter, WaningCresent}

Some of these may not necessarily have a natural order to them, but might just be a set of categories which you could use to organize something in your game. That something could be worlds, or items, or creature types, or powers, or anything else you can think of.

What else?

What else is there? Probably a whole lot! You could probably make a good basis for a game system out of gemstones, or metals, or barnyard animals, or anything, really!

If you know of a set of things that would make a good enum that I’ve left out, leave a comment below.

Using enums in GameMaker Studio

Enums are covered in the manual in the article on Data Types.

The basic syntax is as follows:

First, you have to declare the enum.

enum <variable>{<constant> [= <value>]}

You create the enum using the enum keyword, naming the enum <variable>. Then, in brackets, you list all the constants that make up the values in the enum. You can explicitly declare values for the enum constants, or you can leave them implied, in which case GameMaker will assign them integer values starting at 0, and increasing in order through the collection. You can even use expressions rather than a static value.

To access the enum constants, you use the syntax enum_variable.constant.

In your code, there are all kinds of situations where using an enum is potentially useful. Here’s a few things to look for in your code that might signal a good opportunity to use an enum:

Conditionals for checking state

Consider the following ways of checking the state of some object:

//check state using string matching
if state == "state_idle" {//do state actions}
//check state using literal numbers
if state == 0 {//do idle actions}
//check state using variable
state_idle = 0;
[...]
if state == state_idle {//do state0 actions}
//check state using enums
if state == enum.value {//do state actions}

Out of these, using enums is the best approach. Why are enums better?

Conditional checking by string matching is much slower than number matching. Your string value provides semantic meaning to the reader, making the code easier to understand when a human reads it. But when the program goes to check the conditional, it has to check every letter in both strings to see if they match.

As well, this approach is fairly error prone. It’s very easy to type the strings in slightly wrong. If you’re not careful, it’s easy to type one string where the state is assigned, and another string value where you’re checking state in order to do something state-specific. If you don’t catch the error, you’ll have a hard to diagnose bug because the conditional check won’t match what you’ve set the state variable to. One extra space, or misspelled word, or inconsistent use of capital letters, and the string match check will fail. The compiler won’t help you catch this sort of bug.

It’s a lot faster to do conditional checking via numbers. But naming your states with literal numbers: 0, 1, 2, etc. provides no meaning. Is 0 the idle state? is 1 running? is 2 jumping? Keeping track of this stuff in your head makes your work as a programmer harder, and makes the code hard to read, and brittle. You can do slightly better by creating a named variable and assigning the number value to it. The named variable can be expressive, e.g. state_idle = 0, state_running = 1, etc. But variables values can change, and storing each value takes a little bit of memory. By contrast, an enum value is constant — it cannot be changed once it is declared. And enums are global, so they are only declared and set in memory once, and thus require fewer resources. Even if you have ten thousand instances that use your enum, the memory used by them is the same as if there is only once instance.

Create an enum that provides expressive labels on these values, and you have the best of both worlds: expressive code that checks conditions fast, and uses computer resources efficiently.

Iteration over a set

Conventionally, programmers often rely on conventional looping variable names such as i or j to iterate over a collection of things, such as the members of an array, or other data structure. While this is OK, you can make your code more expressive by using enums to denote important numbers.

For example, it’s common for programmers to use a nested for loop iterating over the variables i and j to create a grid structure. Instead of using i and j, we can use variables named row and column instead. As we iterate over the range of rows and columns, we can use enums as flags to do something special at row (or column) == enum.constant.

Another example:

Say we want to implement an inventory equipping system for the player. The character has inventory slots for head, body, gloves, right hand, left hand, shoes. We decide to create an array, called inventory[], and assign the equipped item in each slot.

We could simply index the array with numbers:

inventory[0] = hat;
inventory[1] = armored_breastplate;
inventory[2] = iron_gauntlets;
inventory[3] = sword;
inventory[4] = empty;
inventory[5] = double_jump_boots;

Now, it’s not too hard to tell what each inventory slot is for. But it’s not as easy as it could be, either. Is the sword in the left hand or the right hand?

Let’s use an enum, and make the code easier understand.

enum inv_slots{head, body, gloves, right_hand, left_hand, shoes};

inventory[inv_slots.head] = hat;
inventory[inv_slots.body] = armored_breastplate;
inventory[inv_slots.gloves] = iron_gauntlets;
inventory[inv_slots.right_hand] = sword;
inventory[inv_slots.left_hand] = empty;
inventory[inv_slots.shoes] = double_jump_boots;

Now, it’s quite easy to see that the double_jump_boots are being worn on the player’s feet, rather than being carried in the player’s hands. It’s simple to keep track of which slot is which.

Creating a set of related, named values

Here’s a useful enum for direction angles for a top-down game:

enum compass {e = 0, ne = 45, n = 90, nw = 135, w = 180, sw = 225, s = 270, se = 315};

It’s much easier to remember and understand direction = compass.sw instead of direction = 225. You can use this enum for 4-direction and 8-direction movement or aiming, and you could even expand upon it if you wanted by adding constants for ene, nne, nnw, wnw, wsw, ssw, sse, and ese, like so:

enum compass {
 e = 0, 
 ene = 22.5, 
 ne = 45, 
 nne = 67.5, 
 n = 90, 
 nnw = 112.5
 nw = 135, 
 wnw = 157.5
 w = 180, 
 wsw = 202.5
 sw = 225, 
 ssw = 252.5
 s = 270, 
 sse = 292.5
 se = 315,
 ese = 337.5
 };

(I like to format my code like this; lining up the variable names, equals signs, and values makes it easy to scan down the file, and makes it clear that these values are all related.)

If I wanted, I could go a step further and use radians to make it clearer that these values are fractions of a circle:

enum compass {
 e = 0, 
 ene = radtodeg(pi * 0.125), 
 ne = radtodeg(pi * 0.25),
 nne = radtodeg(pi * 0.375), 
 n = radtodeg(pi * 0.5), 
 nnw = radtodeg(pi * 0.625),
 nw = radtodeg(pi * 0.75),
 wnw = radtodeg(pi * 0.875),
 w = radtodeg(pi), 
 wsw = radtodeg(pi * 1.125),
 sw = radtodeg(pi * 1.25),
 ssw = radtodeg(pi * 1.375),
 s = radtodeg(pi * 1.5),
 sse = radtodeg(pi * 1.625,
 se = radtodeg(pi * 1.75),
 ese = radtodeg(pi * 1.875)
 };

You can group together, and name other values that go together in a system using enums in this way, too.

Parting thoughts

Hopefully, these examples will help you see how enums can be useful to make your code more expressive, easier to read, and easier to maintain. Look for opportunities to use them in your code. They can really help!

Tutorial: GameMaker Object with multiple collision zones

GM Version: GameMaker:Studio 1.4 (concept should work in earlier versions)
Target Platform: ALL
Example Download: https://csanyk.com/cs/releases/games/LD48-36_AncientTechnologies/LD48_36_Ancient_Technologies_csanyk.gmz
Links: http://ludumdare.com/compo/ludum-dare-36/?action=preview&uid=10473

Summary:

How to make an object that handles multiple collision zones by using multiple sub-objects

Tutorial:

I used this technique in my recent Ludum Dare game, Ancient Technologies. The project has a TON of extraneous code in it, some of which is pretty messy, so I’ll replace the download link with a cleaner example project of just this technique in coming days.

If you look at the Atari 2600 console in this game, it is actually multiple objects, made to look like a single object. This enables each switch to have its own collision detection and mouse events.

I accomplished this with a few simple techniques that work really well:

The console itself is the main object. Then there are 6 objects for the 6 switches on the console.

I then took the image I wanted to use for the sprite, and cut out all the different clickable regions, putting each into its own subimage by itself. Then once all the subimages were created, I removed each subimage into its own sprite, and set the collision mask to cover just the pixels in the image

Atari 2600 clickmap sheet

As you can see, this approach results in a lot of “wasted” space in the sprite sheet in the form of transparent pixels, but if you’re concerned about this, you could always achieve the same effect by using sprite origin and sprite offset to position the images without all the whitespace in the sprite sheet. I skipped using sprite origin because I didn’t feel like bothering with counting pixels and setting each sprite origin differently. That would have been tedious, and if I had ever needed to change the sprites, could have thrown everything off and required extensive rework to recalculate again. If your sprites are tiny, it probably doesn’t matter too much, but if they’re quite large, then you should probably use sprite origin/offset.

(Note: With the small pieces, you’d need to use origin numbers that are larger than the dimensions of the sprite itself, or possibly negative values for the origin. You’d also need to carefully calculate the distance to set the origin so that the images all line up precisely. The goal is to make all the images align when each instance’s x and y are identical. This makes them easy to move around together as a group, without having to deal with offsets and so on. To make everything align easy, I created sprites that have the same height and width, so that getting them to align takes no extra effort or calculation at all.)

Next, use the “main” object to generate the collision zone objects, in the create event:

Note the example code below isn’t exactly the code in my project, but is cleaned up a bit for easier comprehension.

///oConsole Create Event:
power_switch = instance_create(x, y, oPowerSwitch);
tv_type_switch = instance_create(x, y, oTVTypeSwitch);
left_difficulty_switch = instance_create(x, y, oLeftDifficultySwitch);
right_difficulty_switch = instance_create(x, y, oRightDifficultySwitch);
select_switch = instance_create(x, y, oSelectSwitch);
reset_switch = instance_create(x, y, oResetSwitch);

Since these objects all use sprites that are the same size, they all line up together when their x,y position is the same. Now you have an easy way to place just the main object and have it create all of its collision zone objects, perfectly aligned.

If the main object needs to be able to move, you just need to update the x,y of all the objects whenever you need to.

Another great thing is that each of these instances can have its own animation which is completely separate from the rest of the collection of objects. This means you can do really sophisticated animation rigging.

Also, you can access the instance variables of the collision instances by using the main instance, like so:

oConsole.power_switch.position = UP;

is (essentially) equivalent to:

oPowerSwitch.position = UP;

This allows you to use the collision zone instances’ instance variables like you would use properties of a helper class in another language, which may make accessing these variables easier if you’re used to other programming languages.

As well, if each of these switch instances were of the same object, using the id returned by instance_create() would allow you to differentiate between them. This could be useful for, say, a battleship with multiple turrets that are all of the same object type.

Finally, you’ll want to be mindful that if you destroy the main object, you’ll likely want to destroy all the sub-objects. Perhaps not — maybe you’re doing a spaceship with an escape pod or a rocket with multiple stages that break away. But in that case you’ll wan to be sure that once the main object is gone, you are handling whatever remains somehow.

Getting into version control with GameMaker Studio

Version control makes sense whether you are working alone or with a team. It should be a mandatory practice. But you won’t be able to enjoy the benefits of version control unless you know how to do it right. If you’re working with a team, it’s essential that you all know how to do it right. This article will help you get started.

(more…)

Simple GameMaker performance throttling

Here’s a quick tip for performance throttling in GameMaker.

Say you’ve got some code that you need to execute frequently, but if the game starts slowing down too much, you can live without executing this block of code.

Like, for example, say you want to spawn a new instance of some object very frequently, such as in the Step event, but if performance starts to lag you can skip it. You could try to test out how many instances the game can handle without frame rate dropping to an unacceptable level, and cap the number to something somewhat below the maximum. The problem is that this number will vary depending on the hardware. Someone running your game on an older, slower machine will not be able to sustain the same performance that someone with a brand new, high end machine. There really isn’t a true, one-size-fits-all number that works for every situation.

What you really want to do is base the cap on the current performance of the game as it’s running right now. To do that, wrap it up in an if statement like this:

if room_speed < fps
{
 //keep doing the thing that will eventually cause performance issues
}

The way this code works, as soon as fps drops below room_speed, it will stop doing the thing that contributes to the performance problem. This technique does not guarantee that fps will never drop below room_speed, but it will cause performance to stop degrading by not contributing to the problem once performance has degraded to the point that the conditional check takes the “false” branch.

If you don’t want ANY noticeable performance degradation, you may want to make the conditional check be something more like

if (room_speed + 10) < fps

instead; this will give you a little buffer to keep the fps enough above room_speed that you should not see any noticeable performance problems. Or, substitute the calculation room_speed + n with the literal value that you don’t want fps to drop below. Use this to ensure a safer margin of acceptable GameMaker performance.

GameMaker Tutorial: Password systems 3: on-screen keyboard

Yeah, I know. Last article, I said in this article we’d cover parsing and validation and converting the password into gamestate data. We’ll get there eventually. But I want to take a detour and show you how to build an on-screen keyboard.

In the first article in this series, I handled the user input simply, by using the get_string_async() function. This is good enough to be functional, but has two main problems:

First, because we’re allowing input directly from the keyboard, the player can enter any characters at all, which means that we’d need to handle characters that are not part of our password’s alphabet. This means extra programming. Not necessarily a bad thing, if that’s what’s right for the user, but it is more work to write up validation scripts that properly handle our Base64 password alphabet.

Second, the user experience of typing a password into a textbox is fine, as far as it goes, but it isn’t at all like an authentic old school keyboard system. This is a somewhat debatable point — old school consoles used on-screen keyboards not because they were better than keyboard entry, but because there was no keyboard. Entering passwords this way is slower and more tedious. But, if we are going to re-create the experience authentically, we need to heed the conventions of the time.

Every onscreen keyboard in the old days was a custom implementation. No two were exactly the same, although there were a lot of commonalities, and most of the differences were cosmetic. The most common implementation was a grid of characters, which the player selected one at a time using the D-pad, pressing a button to enter the character, and another button to go back. When the entire password was entered, typically the player submitted it by pressing the Start button, or sometimes there was an on-screen button that the player would select with the D-pad. We’ll build something like that in this tutorial, although we’ll use the keyboard rather than a gamepad control. Implementing the gamepad controller input capability isn’t too difficult, though, so I’ll probably come back and add that eventually.

The Alphabet and the Font

One of the problems people have with writing down (and later reading) passwords is that certain characters look very similar (such as 0, o O, l, l, 5, S, 9, g, etc.) You can’t help the player’s handwriting, but at least when the game is displaying the characters on the screen, you should be sure to pick a font that makes these characters unambiguous. These symbols are merely labels which stand for a number value, so it doesn’t really matter what they are.

It’s not a bad idea to omit the similar looking characters, although for this tutorial I’m going to stick with the full alphabet. We’ll at least want a font that has very distinct characters to aid the player in recognizing them correctly. Google for “programmer” or “console” fonts, for suggestions on good ones to use, and pick something out that looks right for the style of game that you’re making. Make sure the capital “I” has serifs and the zero has a slash or dot in it, and so on.

The Onscreen Keyboard Object

oOnScreenKeyboard

Create

alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?";
font = fConsole;
var k = 1;
for (var i = 0; i < 8; i++){
 for (var j = 0; j < 8; j++){
 keyboard[i,j] = string_copy(alphabet,k,1);
 k++;
 }
}
row_selected = 0;
column_selected = 0;
instructions_text = "Press A to select letter. Press B to erase letter. Press Enter to submit password.";

input_string = "";
max_input_string_length = 4;

Draw

draw_set_font(font);
draw_set_halign(fa_left);
draw_set_valign(fa_top);
draw_text(10,10, "PASSWORD: " + input_string);

draw_set_halign(fa_center);
draw_set_valign(fa_middle);

for (var i = 0; i < 8; i++){
 for (var j = 0; j < 8; j++){
 draw_text(x+(32*i), y+(32*j), keyboard[j,i]);
 }
}
draw_rectangle((column_selected * 32) - 16 + x,
 (row_selected * 32) - 16 + y, 
 (column_selected * 32) + 16 + x, 
 (row_selected * 32) + 16 + y, 
 true);

Press Button1

(Pick whatever keyboard key you want for this.)

if string_length(input_string) < max_input_string_length {
 input_string += string_copy(alphabet, (row_selected*8) + column_selected + 1, 1);
}else{
 audio_play_sound(snBadPassword,1,false); 
}

Press Button2

(Again pick whatever keyboard key you want for this.)

input_string = string_copy(input_string,1,string_length(input_string)-1);

Press Enter

if validate_password(input_string){
 apply_password(input_string);
 room_goto(rmGameStart);
} else {
 bad_password();
}

Press Up

row_selected = (row_selected + 7) mod 8;

Press Down

row_selected = (row_selected + 1) mod 8;

Press Left

column_selected = (column_selected + 7) mod 8;

Press Right

column_selected = (column_selected + 1) mod 8;

That's it for the Events, but we need to write three scripts for the Press Enter event. These passwords are where most of the implementation-specific code is going to go.

The details of these scripts will vary from project to project, but this is where we'll handle the validation, parsing, and conversion to gamestate data -- what I thought we'd be covering in this article. We'll cover our example versions of them in the next article.

GameMaker Tutorial: Password systems 2: encoding/decoding

As we established in the first article in this series, a game save password stores game state data. In this article, we’re going to talk about the low level details of how this is done. We won’t be talking much about the password itself, or the game state data. We’ll be focusing instead rather narrowly on how to encode and decode the data.

Numeric data

As far as numeric data is concerned, we’re only going to worry about encoding/decoding integers, for simplicity’s sake. For the most part, we’ll be concerned with positive integers, but we’ll cover negative values as well.

Actually, treating numeric GML data values as integers is a little bit tricky, since in GameMaker the only data types available are strings and reals (floating point numbers). For the most part you can treat a number as though it were an integer in GameMaker, as long as you don’t do math on the number that causes the digits after the decimal point to become non-zero values.

If you want decimal values, you can store the value as an integer, and then divide it by 10, or 100, or however many decimal places as you need after you decode it. Or, if you want to store a fraction, you can store the numerator and denominator as integers, and divide them after decoding them.

As long as you don’t deal in fractions and decimals, you can pretend that your numbers are integers, and GameMaker for the most part will act as though they are. This will come up later when we hit the limit for the largest integer value that we can encode using our method (16,777,215). I’ll explain why below, but for now it’s enough to know this should be a large enough value that we don’t really need to worry about trying to encode larger values, at least for most games.

The basic idea is that each character in your password alphabet stands for an integer value. Notice that the complete alphabet (26 upper case + 26 lower case) + the 10 numerals + 2 special characters gives you a range of 64 values; 2^6 = 64, so each character in a password can represent a 6-bit binary value.

A B C D E F G H
0 1 2 3 4 5 6 7
I J K L M N O P
8 9 10 11 12 13 14 15
Q R S T U V W X
16 17 18 19 20 21 22 23
Y Z a b c d e f
24 25 26 27 28 29 30 31
g h i j k l m n
32 33 34 35 36 37 38 39
o p q r s t u v
40 41 42 43 44 45 46 47
w x y z 0 1 2 3
48 49 50 51 52 53 54 55
4 5 6 7 8 9 ! ?
56 57 58 59 60 61 62 63

Beyond 63

What can you do if you want to store a value larger than 63? Simple, you just use a second digit in your base-64 number. Just like the next number after 9 is 10, in base-64 the next number after ? is BA. Until you’ve looked at base-64 numbers for a long time, it’s going to be very difficult to recognize the value represented by a base-64 number, but we don’t need to — we’ll tell the computer to do it for us with some gml scripts.

We said before that a 4-digit base-64 number stores 24 bits, or up to 16,777,215 in base-10. But for some numbers that might be overkill. If we wanted to, we could treat each digit as a single base-64 value, and add them together. For a 4-character base-64 string, this would give us a range of 0-252, nearly a byte. It’s a much less compact way of storing the data, but for small values it’s not too bad.

To do the conversion from base-10 to base-64 and back, we’ll need some gml scripts.

b64_to_dec(b64)

/*
Takes a string of a b64-encoded value and converts it to a real number
*/
var b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?";
var value = 0;
var digit = 0;
var neg = 1;

if string_copy(argument0,1,1) == "-"{
 argument0 = string_copy(argument0,2,string_length(argument0)-1);
 neg = -1;
}

for (var i = string_length(argument0); i >= 1; i--){
 value += (string_pos(string_copy(argument0,i,1), b64_alphabet)-1) * power(64,digit); 
 digit++;
}

return neg * value;

/*
Takes a real number and converts it to a base-64 encoded string. Supports integer values from 0-16777215.
*/

var b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?";
var value = abs(argument0);
var r;
var str = ""; 
var done = false;

while !done{
 r = value mod 64;
 str = string_char_at(b64_alphabet, r+1) + str;
 value = (value - r) div 64;
 if (value == 0){done = true;}
}

if (argument0 < 0){
 str = "-" + str;
}

return str;

Lastly, it will be handy to have a function that can pad a B64 encoded string to a specific length:

b64_padded

/*
Takes a base-64 encoded string (argument0) and pads it to padded_length (argument1) with leading "A"'s (0's). 
If the number is negative, the first character in the padded string will be a "-". If the padded_length is 
less than the length of the b64 value, the function returns -1 to signify an error. 

(Note the error code returned is a real number, -1, not to be confused with the correct output of 
b64_padded(-1,2), which would return the *string* "-1") 
*/

//argument0 the b64 string to pad to length
//argument1 the length to pad to

b64 = argument0;
len = argument1;

if len < string_length(b64){return -1;} //too short, return error
if len == string_length(b64){return b64;} //just right; we're already done

var str = "";
if string_copy(b64,1,1) == "-"{
 str = "-";
 len--;
 b64 = string_copy(b64,2,string_length(b64)-1);
}
repeat (len - string_length(b64)){str+="A";}
str+=b64;

return str;

Negative Numbers

The scripts above handle negative values just fine. But the minus sign is not part of the base-64 alphabet. If we need to store negative numbers, we have a few choices.

We can expand our password alphabet to include a minus sign (or an arbitrary symbol that we can use as a substitute).

Or we can designate certain characters in the password to store a boolean which signifies whether a given numeric value stored elsewhere in the password is positive or negative. Then encode the absolute value of the number, and re-combine it later with the boolean that holds the sign.

Or we can sacrifice a bit in our base-64 encoded numbers and treat them as signed integers, such that A-g represent values 0 through 32, and h-? represent negative values -1 through -31.

Beyond 16,777,215?

The encoding/decoding scripts work for values up to 16,777,215, or ???? in b64. This value is (2^24)-1. Beyond that, the numbers do not encode/decode properly. The reason for this has to do with the way GameMaker stores numeric values. All numbers in GameMaker are floating point values. GameMaker uses a 32-bit floating point, of which 24 of those bits are used for the digits to the left of the decimal point. The remaining 8 digits are used for the fractional value to the right of the decimal point. This means that for a number above 16777215, we can’t store the value in a 32-bit floating point variable without losing some precision. This precision prevents us from cleanly encoding a value above 16777215 and decoding it back to the same value. Fortunately, such high values should be rare to encounter in the game state data.

What happens if you try to store a larger value depends on the build target. Some may lose precision, resulting in off-by-one conversions — data corruption. Others may fail to return a value entirely when the conversion script is called, which would result in total loss of the data. Certain build targets (I’m not certain which ones) may use 64-bit floating point values, rather than 32-bit. In this case, we can go even higher, up to (2^52)-1. This is a ridiculously large number, and it’s almost certainly more than enough for any game state value you might want to encode.

Tip for validation

If the password space allows a value larger than the max value for a given game state variable, you can use those larger values as a form of validation check. For example, let’s say that the maximum number of lives in your game is 255. This requires an 8-bit value, but since each character represents 6 bits, and we don’t want to bother splitting characters, we use 2 password characters, which represents 12 bits of data. We can use these additional value space between 256 and 4096 for a validation check.

The simplest method would be to reject any password that contains data in the lives bits that decodes to a value greater than 255. Another way to handle this is to use a math value to obfuscate the lives value. Since 4096/256 = 16, we can take the value of the two characters that we use to encode the lives count as follows: lives x 16 = password substring. Now, when you’re validating the password, you can mod the value of the characters that represent the lives by 16, and if the calculation doesn’t work out to 0, then you know the password isn’t valid.

Or you can make the “right” remainder be dependent upon some other part of the password — for example, when the Level is even, the lives substring should mod16 to 0, but when Level is odd, it should mod16 to 1, unless Level is divisible by 3, in which case… Sneaky/unnecessary complexity like this will make the password harder to understand, and therefore require more effort to crack the password system. Don’t fool yourself into thinking you’re coming up with a super secure uncrackable password, but it will make the password a little less obvious than a simple counter, and for password system crackers, will make the puzzle more fun.

String data

Old NES password games did not typically have any string variables to preserve in a save password. In fact, the few games where you could enter a name were all, to the best of my knowledge, battery backup games that used savefiles.

It’s simple enough to store a string in a password, though, since a password is a string. The only real issue is dealing with variable length strings. For a lot of reasons, it’s probably best to stick with a fixed length for strings and pad shorter strings with spaces, trimming them later when applying the password to game state.

However, it looks weird if your password has string values stored as plain text in the password — it’s an obvious indicator to the player that the password is storing data, which could invite mischief. So it’s probably a good idea to encode the data somehow.

We could encode strings by using the numeric ASCII values of the letters, and then convert them back, character by character. While not encrypting the data, it would be sufficiently obfuscated for our purposes.

I won’t bother implementing this for now, since our demo password only has 4 characters, and in any case it’s not really necessary, but it’s good to have an idea of how we might do it if we decide to later on.

Boolean data

GameMaker doesn’t have a true boolean data type. The boolean constants true and false are equal to 1 and 0 in GML. Boolean expressions in GameMaker are handled by evaluating to a real number, and any number <0.5 evaluates as false, and 0.5 or greater evaluates as true. Therefore, to encode a boolean, all we really need to do is encode a value of 0 or 1. Or any other value that will evaluate to true or false.

But, since a single base-64 character can store up to 6 bits of data, and each bit can store a 0 or a 1, a single character could in theory store up to 6 boolean values, which means a 6x greater density than if we just stored one boolean value in each character.

To achieve this, we need to convert a base-64 value to a binary value, and vice versa. Then we would need to break the binary value into its individual bits, and designate each bit for a specific boolean value.

Note that the next few functions do not really deal with binary values, but rather with strings storing 0 and 1 characters, which we can convert to boolean values by using the real() function.

Edit: I’ve updated these functions with more elegant implementations, and replaced the brute force switch statement lookup table approach that I had here originally. Thanks to Ian Schreiber for the suggestion.

bin_to_dec(bin)

/*
Takes a string of a binary encoded value and converts it to a real value.
*/
var bin_alphabet = "01";
var value = 0;
var digit = 0;

for (var i = string_length(argument0); i >= 1; i--){
 value += ((string_pos(string_copy(argument0,i,1), bin_alphabet)-1) * power(2,digit)); 
 digit++;
}

return value;

dec_to_bin(dec)

/*
Takes a base-10 value and encodes it as a binary string
*/
var bin_alphabet = "01";
var r;
var str = "";
var done = false;
neg = sign(argument0);
value = abs(argument0);

while !done{
 r = value mod 2;
 str = string_char_at(bin_alphabet, r+1) + str;
 value = (value - r) div 2;
 if (value == 0){done = true;}
}

if (neg < 0) {str = "-1" + str;}

return str;

bin_to_b64(bin)

/*
Takes a 6-digit binary encoded string and converts it to a b64-encoded character.
*/

return dec_to_b64(bin_to_dec(argument0));

bin_to_bool(bin)

/*
Extracts the argment1-th bit out of the binary string supplied in argument0 and returns it, converted
to a real number. The real value can be interpreted as a boolean (0=false; 1=true).
Argument0 must be a string consisting only of "0"'s and "1"'s
Argument1 must be a number between 1 and string_length(argument0). 
*/

return real(string_copy(argument0,argument1,1));

bool6_to_bin(bool,bool,bool,bool,bool,bool)

/*
Takes six boolean values and concatenates them to create a 6-bit binary encoded string, 
suitable for converstion to a b64 value with the bin_to_b64() function.
*/

/*
force conversion of arguments to gml boolean constants
*/

if argument0{argument0 = true;}else{argument0 = false;}
if argument1{argument1 = true;}else{argument1 = false;}
if argument2{argument2 = true;}else{argument2 = false;}
if argument3{argument3 = true;}else{argument3 = false;}
if argument4{argument4 = true;}else{argument4 = false;}
if argument5{argument5 = true;}else{argument5 = false;}

/*
concatenate bools to string
*/
return string(argument0) + string(argument1) + string(argument2) +
 string(argument3) + string(argument4) + string(argument5);

bin_padded

//pads a binary encoded string (argument0) to length (argument1)
var bin = argument0;//bin string to pad
var len = argument1;//padded length

if len < string_length(bin){return -1;}
if len == string_length(bin){return bin;}

repeat(len - string_length(bin)){bin = "0" + bin;}

return bin;

These scripts should suffice for encoding/decoding all of our data values.

Advanced password validation with checksums and hashes

Additionally, to keep the player honest, you probably want some kind of tamper-proofing to go with your password encoding. Otherwise, it makes tinkering with the password to cheat too easy. For example, you could play the game, get a password, then get hurt, and get a new password, and by comparing the two, you could infer which characters in the password correspond to your health. Then, you could substitute different values for the password characters that correspond to your health health until you hit upon a value that gave you max health, or, depending on how the game works, even infinite health or invulnerability.

It’s true that deciphering password encoding schemes is a lot of fun, but we don’t want to make the system so easy that it invites cheating. Make the player work at it, and feel like they truly hacked something when they figure out your system.

To do this, we can reserve certain characters in the password for storing checksum values, or even hash values. Understanding hash and checksum math isn’t too difficult, but isn’t terribly necessary, either. We don’t need something impossible to crack, just something functional. There are better checksum functions than I’ll demonstrate here, but this should suffice to make the concept understandable to anyone.

Simple checksum

Using our 4-character example password, we can add an additional two characters for checksum data.

Level Lives Health Ammo Checksum
A-? A-? A-? A-? AA-??

Let’s say the game state data is encoded with the following 4 values from our cipher table, above:

Level Lives Health Ammo
password char B D ? ?
base-10 value 1 3 63 63

A simple checksum for this would be 1+3+63+63 = 130. Of course, this checksum isn’t very strong; any four values for Level, Lives, Health, and Ammo that add up to 130 will have the same checksum. But it does stop someone from changing a single character in the password and getting another valid password.

To add the checksum value to the password, we need to encode 130 as a base-64 value. This would be a 2-digit base-64 number: 22. According to our base-64 encoding table, the value 2 is encoded by the symbol C. So, 22 == CC. So the entire password would be:

Level Lives Health Ammo Checksum
password char B D ? ? CC
base-10 value 1 3 63 63 130

Note that since 63*4 = 252, the highest the checksum value will ever go will be 252, or D8.

If you wanted to get really crazy, you can scramble the order of the characters, shuffling checksum characters in between the data value characters. But we’re not that concerned with obfuscation, so we won’t bother with an example of this.

In the next article, we’ll cover how to design the password specification in greater detail, and write some sample scripts that takes the password, validates and decodes it, and assigns the stored values to re-create the game state.

Part 3