We would love you to play this but your browser doesn't support HTML5 canvas.
Just use a different browser and you can happily play this game.

How to do Masking in GameMaker

Masking is easy in GameMaker and I’m going to show you how! It's important you know how to do masking in GameMaker, once you know how to utilise masking it can be used in many technologies like outlines, field of views, drop shadows, reflections and wall destruction.

What is masking?

In the above example you can see masking in action, it is a way that you can delete part of an image. I will show you how you can use an image to select parts of a separate image that will not be drawn to the screen so you will basically see through those parts of the image.

There is so little code to do this I am going to put the code first and talk about how it works after.

The Code :
// draw event:

if (! surface_exists(surfacewithmask)) {surfacewithmask = surface_create(room_width, room_height); }

surface_set_target(surfacewithmask)

draw_sprite(spr_tomask,0,0,0);

draw_set_blend_mode(bm_subtract)
draw_set_colour(c_black)
draw_circle(mouse_x,mouse_y,80,false)
draw_set_blend_mode(bm_normal)

surface_reset_target();

draw_surface(surfacewithmask,x,y)
    
How does it work?

I have two images that are the same size as the room, the top image and the bottom image. The top image has a hole taken out of it that allows you to see through it and to the image below. Let’s talk about how we can do this.

First we have to create a surface, if you don’t know what a surface is in GameMaker its basically an image that we can draw onto just like we normally draw onto the screen, we can then draw this surface onto the screen just like we would a sprite. I will point out here that you always need to check if a surface exists before you call it because they are volatile and can be removed from the graphics memory.

surface_set_target() – Normally in GameMaker when you say draw_text() or draw_sprite() you just expect them to be drawn to the screen, well using surface_set_target() we can actually tell GameMaker to draw onto a surface we have made rather than the screen.

I now draw the whole top sprite onto the screen using the standard draw_sprite().

draw_set_blend_mode(bm_subtract) - Here I need to remove a hole from the top image like I had an eraser, we do this with draw_set_blend_mode(bm_subtract). There are other blend modes you can use however we will be using bm_subtract which rather than drawing each pixel will remove the colour value instead of adding one in.

At this point it is worth just highlighting that we have told GameMaker to draw onto the top surface rather than the screen AND everything it draws should be deleted from the image. Anything we draw at this point will be deleted, we could draw as many things as we liked here however I’m just going to draw a circle where the mouse is.

draw_set_blend_mode(bm_normal) and surface_reset_target() – These just set GameMaker back to how you normally do things, you have to set these back because GameMaker will not let you continue and will crash if you don’t set these back.

Now I just need to draw the two images, first the bottom image and then place the top image with the hole over the top of it!

Easy Peasy!

Changing the mask area :

So you might want to do an animated mask or a transparent mask like I put in my example. This is really trivial because anything you put between the draw_set_blend_mode() functions will be removed from the mask. You could draw many animated, semi-transparent sprites and all of them will just remove that area from the surface. It doesn’t matter what the colour is, the more opaque that part of the image the more it will remove (pure black will totally delete that part of the surface and semi-transparent parts will only partly delete that part of the surface).

Here is an example of the images I used:

Masks :

I have used masks to do Complex Outlines in GameMaker and Field of Views in GameMaker so if you are looking to do that those guides will be good further reading.

HTML5 and WebGL :

It was really important to me that this was a HTML5 compatible version of masking, so if you have the GameMaker HTML5 module you can use it on websites like I have done above. I did try turning WebGL off on the version above once and it didn’t work, I didn’t try to fix it and with a bit of work you might be able to get it working with WebGL off However this really isn’t a problem for because the latest version of most browsers support WebGL.

Optimising changes you might want to make :

Optimisation 1; Normally you would free the surface once you have stopped using it using surface_free() however in this demo there is no point in doing this.

Optimisation 2; To make the code easier to read above I put it all in the draw event, this works but really you should save the draw event to have only the most necessary code running in it. For example the surface_create(room_width, room_height) should be put in the create event, but if you do make sure that you still check it exists because as GameMaker says in the manual surfaces are volatile and a devices might remove them from the graphics memory when your program is not being used.

Optimisation 3; The GameMaker Manual does tell you to use surface sizes that are powers of two like: 16, 128, 512, 1024 etc. I never have and this is might be why I have so many problems with surfaces.

Optimisation 4; Something you should do is only remake the mask and the surface if something has changed. It would be quite simple to cache it with just a flag saying changed=true and I think this will really help. I dont need to do it above becuase it runs perfectly fine at 60pfs

Full project code :

For those of you who want it I have made the full project code available here to download.

Credits :

You don’t think I did all those graphics above do you? Nope they were done by Wolthera van Hövell tot Westerflier, Lanea Zimmerman and Parakoopa

About the Article:
Medium Difficulty
GameMaker
By David Strachan