Creating a Memory Match Game in GDevelop

by komencanto

This tutorial is based on the tutorial “Creating a Memory Match Game in Construct 2” by kittiewan:

https://www.scirra.com/tutorials/280/creating-a-memory-match-game/page-4

Part 3 (easy)
Part 3 (advanced)

Part 4: Turn of play

(Using function mod, a timer; restarting the game)

In the previous parts we layed out our cards and shuffled them.

In this part we'll implement the turn of play.

When two cards are turned face up we'll check them for matches. If they match, they will be removed from the play, if they don't match they will be turned back with back side up.

Before we begin to work on this part let's deactivate the shuffling of the cards to make testing of our game easier. Right click on the event 'Repeat 50 times:' and choose De/activate.

Then if you laid out your cards by advanced method go to the list of global variables and change:

gNumberCards = 12
gNumberRows = 3
gNumberColumns = 4 (must be gNumberCards divided by gNumberRows)

This way we'll have less cards to test.

I. Turning two cards face up

To know if two cards are selected we'll need a global variable gCountCardsPicked. If it's less then 2 we can choose another card. If it's equal 2 we'll check for matches.

So, create the global variable gCountCardsPicked (Right click on Project, choose 'Modify global variables', plus sign).

Then, in the mouse event under sub-event where we check if the Left mouse button is pressed, add a sub-event:

Conditions:
Variables - Global variables - Value of a global variable
Variable: gCountCardsPicked
Sign of the test: <
Value to compare: 2

And for actions move all actions from the sub-event above in this sub-event, and add two actions to increase gCountCardsPicked by 1 and change FaceUp of the chosen card to 1:

Actions:
1. Variables - Global variables - Value of a global variable
Variable: gCountCardsPicked
Modification's sign: +
Value: 1

  1. All objects - Variables - Modify a variable of an object
    Object: card
    Variable: FaceUp
    Modification's sign: =
    Value: 1

Then we need to create two more global variables to keep in them the values of CardFrame of the selected cards which we need in order to find out if they match or not.

So, let's create these global variables:

gFirstCardFrame = 0
gSecondCardFrame = 0

Create another sub-event to the sub-event 'gCountCardsPicked<2' to check if the first card was selected and to store its CardFrame value in gFirstCardFrame:

Conditions:
Variables - Global variables - Value of a global variable
Variable: gCountCardsPicked
Sign of the test: =
Value to compare: 1

Action:
Variables - Global variables - Value of a global variable
Variable: gFirstCardFrame
Modification's sign: =
Value: card.Variable(CardFrame)

And add another sub-event (at the same level that the above one) to check if two cards are selected and to store the value of CardFrame of the second card:

Copy the previous one and change:

Conditions:
Value to compare: 2

Action:
Variable: gSecondCardFrame

This part of events shall look like this:

II Checking the cards for matching

Let's create a new event at the bottom of our event list which will check if two cards are selected and if they match or not. (Select 'The cursor is on card' event and click on button 'Add an event'.) You can add a comment before it which says: “Checking for matching”.

Conditions:
Variables - Global variables - Value of a global variable
Variable: gCountCardsPicked
Modification's sign: =
Value: 2

Add a sub-event to it to check if the cards match:

We'll use a comparison function with some mathematical expressions with modulus function (mod) in them:

Conditions:
Other - Compare two expressions:
Expression 1:
GlobalVariable(gFirstCardFrame)-mod(GlobalVariable(gFirstCardFrame),2)

It says: subtract from the gFirstCardFrame a reminder from the division of gFirstCardFrame and number 2 which results in 0 or 1.

Sign of the test: =
Expression 2:
GlobalVariable(gSecondCardFrame)-mod(GlobalVariable(gSecondCardFrame),2)

It's the same expression but for the second card.

(Remember, that frames of our cards are arranged in pairs, which form matches: 0 and 1 - match, 2 and 3 match and so on.
The function mod(frame,2) will return '0' if a frame number divided by 2 have no reminder (an even number divided by 2) and '1' if there is a reminder which equals 1 (an odd number divided by 2).
So, mod(0,2)=0, mod(1,2)=1, mod(2,2)=0, mod(3,2)=1 etc
Now, if you subtract this reminder from the odd frame number it will give you the even frame number of the matching card.
Frame 1 - mod(1,1) = 1-1=0 → equals to matching frame 0.
Frame 3 - mod(3,1) = 3-1=2 → equals to matching frame 2 etc.)

Add a sub-event to check if the card is face up:

Condition:
All objects - Variables - Value of an object's variable
Object: card
Variable: FaceUp
Sign of the test: =
Value to test: 1

So, when two cards match and they are face up, we'll delete them:

Action:
All objects - Objects - Delete an object
Object: card

Add the second sub-event to the main event where we check if gCountCardsPicked = 2. (Select the first sub-event of it and click 'Add an event' button. It will be added under the first sub-event at the same level.)

In this sub-event we'll check if the cards don't match.

So, copy the condition from the previous event and change the “=” sign to “!=” which means 'not equal'.

Add a sub-event to it to check if the cards are face up to turn them back:

Condition:
All objects - Variables - Value of an object's variable
Object: card
Variable: FaceUp
Sign of the test: =
Value to test: 1

In actions we'll change the animation of the cards and their FaceUp variables to 0:

Actions:
1. Sprite - Animations and images - Change the animation
Object: card
Modification's sign: =
Value: 0

  1. All objects - Variables - Modify a variable of an object
    Object: card
    Variable: FaceUp
    Sign of the test: =
    Value to test: 0

And now we need to add the third sub-event to our main event of checking if gCountCardsPicked = 2. And in it we need to set the value of gCountCardsPicked back to '0' to be able to check next pair of cards for matching.

Conditions: No conditions
Action:
Variables - Global variables - Value of a global variable
Variable: gCountCardsPicked
Modification's sign: =
Value: 0

So, now if we run our game, when we click on two cards they disappear when matched and turn over when not.

But we have a problem: after clicking the second card we don't see when it turns face up - it does it too quickly. So we need to add a pause before checking if cards match.

To do this we'll use a timer. We need to reset the timer when we need a pause and check its value before proceed to checking for matches.

Let's make another global variable gCardResetDelay = 1 (seconds). We can change this value later if we want to.

Now, add an action to the sub-event 'gCountCardsPicked = 2' of the Mouse event under 'Do =card.Variable(CardFrame) to gSecondCardFrame' to reset the timer:

Action:
Timers and time - Reset a timer
Timer's name: “pause”

Now in the event of checking for matches under condition 'gCountCardsPicked = 2' add another condition to check if passed 2 sec after the resetting of the timer “pause”:

Condition:
Timers and time - Value of a timer
Time in seconds: GlobalVariable(gCardResetDelay)
Timer's name: “pause”

Now try to run our game. After you select two cards they turned face up and stay this way for a while before turning over or being deleted.

But you can notice another problem: when we click on one card twice the program assumed that you found the match and delete it.

Let's add another condition to a sub-event 'gCountCardsPicked < 2' of the Mouse event in which we'll check if the card picked is not face up.

Condition:
All objects - Variables - Value of an object's variable
Object: card
Variable: FaceUp
Sign of the test: =
Value to test: 0

That shall do the trick.

This part of events shall look like this:

III Restarting the game after all matches were found

Now let's make our game restart after we've found all matches.

To do that we need to know how many matches were made.

So, let's create a global variable gMatches.

When the match is found this variable will increase by 1.

When it equals to number of pairs of our cards the game can be restarted.

So, find the sub-event when we check if two cards are matching and add an action to it to increase gMatches by 1:

Action:
Variables - Global Variables - Value of a global variable
Variable: gMatches
Modification's sigh: +
Value: 1

And to the end to our program add an event where we'll check if gMatches = gNumberCards/2 (to half of number of our cards).

Note: If you layed out the cards by hand then create a global variable gNumberCards = 12

So, our new event (at the bottom of the event sheet) will be:

Condition:
Variables - Global variables - Value of a global variable
Variable: gMatches
Sign of the test: =
Value: GlobalVariable(gNumberCards)/2

And add actions to set gMatches back to 0 and restart the game:

Actions:
1. Variables - Global variables - Value of a global variable
Variable: gMatches
Modification's sign: =
Value: 0

  1. Scene - Go to a scene
    Name of the scene: "Game"

If we run our game for a native platform the preview will not show when the game is restarting - you need to compile the game to see how it restarts (which is not very convenient) or you can temporarily switch a platform to the Web platform.

To do the last one double-click on 'Extensions' in the 'Project manager'. Right click on 'Web platform' and choose 'Use this platform'. Right click on 'Native platform' and choose 'Do not use this platform anymore'. Click on the 'Close' button on bottom of the window. Then close and reopen our scene 'Game'.

Now, when you click 'Preview' the game will be opened in the web browser and you can test how it restarts.

(Note: There is another bug for a Web platform where SceneWindowWidth() and SceneWindowHeight() returns the size of the whole browser window, not the part of the game window. So, to fit our cards properly in the browser window you need to manually change the size of the browser window to 640×480 or to replace those expressions by numbers in our events: SceneWindowWidth() → 640, SceneWindowHeight() → 480.)

You'll notice that the game restarts a little too fast. We need to add a delay before restarting it.

To do that we'll use another timer “GamePause”. The delay time we'll be 5 sec.

So, create the global variable
gGameResetDelay = 5.

Copy and paste the last event. In the original copy we'll need to add a condition to trigger this event only once when it will be true and for action we'll reset the timer “GamePause”.

So, add a condition in the event under 'gMatches=gNumberCards/2':

Condition:
Advanced - Trigger once while true

Action:
Timers and time - Reset a timer
Timer's name: “GamePause”

Delete other two actions from it.

In the second event under the same condition 'gMatches=gNumberCards/2' add another condition to check if 5 seconds passed after the resetting the timer.

Condition:
Timers and time - Value of a timer
Time in seconds: GlobalVariable(gGameResetDelay)
Timer's name: “GamePause”

Actions will be those two, which we copied from the event above ('gMatches=0', 'Go to scene “Game”').

This part of events shall look like this:

Now we have a working copy of our Memory Match Game.

The source file of this part:
Easy version: https://drive.google.com/file/d/0B4iAICUekZv0Z3NSRmxXRkM4VWM/view?usp=sharing
Advanced version: https://drive.google.com/file/d/0B4iAICUekZv0U1hJYW9Mcy1wUUU/view?usp=sharing

In the next chapter we'll add finishing touches to it (text messages and sounds).

Part 5