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.

Programming a Scratch Card (Scratch-Off) in GameMaker
(HTML5 compatible)

Some people in the world know these as Scratch-Offs. Whatever you call them they are the cards with a metallic layer on that you scratch off to see what it under that panel.

I was playing Rayman Legends and I thought it was incredibly clever how rather than just unlocking bonus levels and creatures they give you a scratch card. Even if the scratch card doesn’t change the unlock the player gets they will still feel responsible and more attached to the reward than if you just popped up a message saying: “You unlocked this upgrade!”.

The scratch card from Rayman Legends courtesy of HiddenSwitch:
Rayman Legends scratch card

So as you can see from the example above I thought I would write a little guide to show anyone how to make a scratch card in GameMaker in the hopes that more people will add them into their games.

I am aware this is not going to be very useful for a lot of people, I cant imagine there are many people searching: “how do I make a scratch card in GameMaker”. However stick with me because we are going to learn some interesting techniques. And like I said before, I think they can be used to improve the simple task of rewarding the player into something that is more involved.

In the interactive demo at the top you can just click your mouse to reveal the hidden panels. Once you have unscratched all 6 items under the panel it will give you a new card but change the shape that you scratch off with.

Once you finish this guide all you will need to do is add some sounds and maybe some little filings that get knocked around and it will look lovely in your game.

How does it work?

I am using two images the bottom image which has the background and the card on and the top image which has the metal on it. I am using GameMaker surfaces to make a temporary image that holds the top image of the metal on it and with some code that I will show you I can edit this top image to remove some of it so you can see the card below it.

Programming a Scratch Card in GameMaker
Programming a Scratch Card in GameMaker

If you haven’t used surfaces before I have some excellent guides on them for doing masking in GameMaker. However this guide will be pretty simple and all you need to know about surfaces at the moment is that they are basically a blank canvas we can draw onto just like we would draw onto the screen, these surfaces can then themselves be drawn onto the screen with everything you have added onto them.

I am going to break this guide into two parts first we will look at how we scratch off the metal cover as this is likely to be the more complex part. After that I will look at finding which areas have been scratched off.

Scratching the metal off :

I used one object to draw the metal cover and work out what parts have been removed. This is the code for that:

CREATE:

/// Make the surface and prime it with the image of the metal 

surfacemetal = surface_create(sprite_get_width(spr_metal), sprite_get_width(spr_metal));

surface_set_target(surfacemetal)
draw_sprite(spr_metal,0,0,0);
surface_reset_target();
    

STEP:

/// If the player is clicking remove an area from the metal surface
if(mouse_check_button(mb_any)) {
    if (surface_exists(surfacemetal)) {
	surface_set_target(surfacemetal)
	draw_set_blend_mode(bm_subtract)
	draw_set_colour(c_black)
	draw_circle(mouse_x-x,mouse_y-y,25,false)
	draw_set_blend_mode(bm_normal)
	surface_reset_target();
    }
}
    

DRAW:

/// draw the metal 

if (surface_exists(surfacemetal)) {
    draw_surface(surfacemetal,x,y)
}
    

So let’s break down how that works:

In the create event I am making a surface that I called surfacemetal I then add the image of the metal to it.

In the step event I am working out if the user is clicking. If so I use surface_set_target() and draw_set_blend_mode() to clear a circle in the metal image so you can see the card below.

surface_set_target() – As I said before that surfaces can be drawn onto just like we draw onto the screen, however any changes are permanently kept. Using surface_set_target() we tell GameMaker to stop drawing onto the screen and start drawing onto the surface. You must remember to reset this after with surface_reset_target().

draw_set_blend_mode(bm_subtract) – Using this function we tell GameMaker that anything we tell it to draw should actually delete like an eraser. You must remember to reset this after with draw_set_blend_mode(bm_normal).

Using surface_set_target() and draw_set_blend_mode() together we can do Masking in GameMaker

Finally in the draw event we check that the surface still exists and then draw the metal surface on top of the card with any holes in it the player might have removed. The reason we need to check it exists is because surfaces can be volatile in GameMaker and are prone to be removed from the video memory. To stop this crashing the game we just use: if (surface_exists()).

Finding what points have been scratched off :

So let’s now look at how I detect what areas of the card have been seen. This is just the way I have chosen to do it, you might want to write this in a style you are more familiar with or that fits your game better.

I have used one object to work out which areas have been seen. The reason I did this is for me each area is the same size and has the same image, also it allows me to quickly add as many areas as I liked.

CREATE:

// the location of each objective
objectivelocationx[0] = 0
objectivelocationx[1] = 80
objectivelocationx[2] = 160
objectivelocationx[3] = 0
objectivelocationx[4] = 80
objectivelocationx[5] = 160


objectivelocationy[0] = 0
objectivelocationy[1] = 0
objectivelocationy[2] = 0
objectivelocationy[3] = 70
objectivelocationy[4] = 70
objectivelocationy[5] = 70

// to mark each objective as seen or not
objectiveseen[0] = false
objectiveseen[1] = false
objectiveseen[2] = false
objectiveseen[3] = false
objectiveseen[4] = false
objectiveseen[5] = false

// just to count when they have all been seen 
seen=0
    

STEP:

if (mouse_check_button(mb_any)) {

    var loopamount = array_length_1d(objectiveseen)

    for (i=0; i<loopamount; i++) {
	var relmousex = mouse_x-x
	var relmousey = mouse_y-y

	/// we set how close the mouse needs to get here
	if (point_distance(relmousex,relmousey,objectivelocationx[i],objectivelocationy[i]) < 20) {

	    if (objectiveseen[i] == false) {
		objectiveseen[i] = true
		seen ++ 
	    }

	}
    }

}

if (seen >= 6) {
    if (instance_number(obj_allseen) = 0) {
        instance_create(room_height+10,room_width/2,obj_allseen)
    }
}
    

DRAW:

/// draw if an objecting has been seen or not

var loopamount = array_length_1d(objectiveseen)

for (i=0; i<loopamount; i++) {
    
    if (objectiveseen[i] == true) {
        draw_sprite(spr_objective,0,x+objectivelocationx[i],y+objectivelocationy[i])
    } else {
        draw_sprite(spr_objective,1,x+objectivelocationx[i],y+objectivelocationy[i])
    }

}
    

How this works is by first allocating a position for each of the objectives. I then keep checking to see if the mouse is clicked and if it is within 20 pixels of an objective. If it is I mark it as seen and increase a count by 1. Once this count gets to 6 I know the player has uncovered all of the objectives.

I was very particular about the distance needed to mark an area as uncovered. Because I think from a psychological point of view it is better to hint at what it to come before you give it to the player. Most of the time the player will just instantly scratch off the surface, but for those few occasions when they only partly reveal the reward I think it is more satisfactory for them knowing what is to come.

Different brushes :

If you want to have different brushes it is really easy to do, all you need to do is remember is you can draw anything you want in the metal surface step event and it will be removed.

Standard:

if (surface_exists(surfacemetal)) {
    surface_set_target(surfacemetal)
    draw_set_blend_mode(bm_subtract)
    draw_set_colour(c_black)
    draw_circle(mouse_x-x,mouse_y-y,25,false)
    draw_set_blend_mode(bm_normal)
    surface_reset_target();
}
    

Textured:

Programming surface GameMaker
if (surface_exists(surfacemetal)) {
    surface_set_target(surfacemetal)
    draw_set_blend_mode(bm_subtract)
    draw_sprite(spr_texture,0,mouse_x-x,mouse_y-y)
    draw_set_blend_mode(bm_normal)
    surface_reset_target();
}
    

Transparent:

if (surface_exists(surfacemetal)) {
    surface_set_target(surfacemetal)
    draw_set_blend_mode(bm_subtract)
    draw_set_alpha(0.06)
    draw_set_colour(c_black)
    draw_circle(mouse_x-x,mouse_y-y,25,false)
    draw_set_alpha(1)       
     draw_set_blend_mode(bm_normal)
    surface_reset_target();
}
    

Animated:

Programming surface GameMaker
if (surface_exists(surfacemetal)) {
    surface_set_target(surfacemetal)
    draw_set_blend_mode(bm_subtract)
    animationangle++
    draw_sprite_ext(spr_star,0,mouse_x-x,mouse_y-y,1,1,animationangle,c_white,1)
    draw_set_blend_mode(bm_normal)
    surface_reset_target();
}
    
HTML5 and WebGL compatible :

All of the features of this guide are compatible with the GameMaker HTML5 module. I’m quite sure you don’t need to tick WebGL enabled in the Global Game Settings however I always tick the box now to make WebGL required just so I don’t need to test and support the two different versions.

Just for anyone having problems using the demo at the top :
Example Scratch Card Code
About the Article:
Medium Difficulty
GameMaker
By David Strachan