Memory Match in Modern Javascript with Phaser 3 - Part 5

A more involved game for beginners to Phaser 3 and modern JavaScript

by on 6 minute read


If you've gone through the basic first game in modern JavaScript or the infinite jumper book then you've got the basics down so let's try making something a little bit more complicated!

We suggest Memory Match. A Mario Party-inspired memory game where you control a character to pick boxes until all matches are found within a limited amount of time.

In part 4, we fixed a couple of bugs left over from part 3 and handled the cases for a match or no match.

For this part 5, we'll add logic that stuns the player when the bear is revealed and then check for level complete when all matches have been made.

We also have a video version on YouTube if you prefer to watch or want to see how it is coded in real-time.

Stay Away From Bears

In Mario Party's memory match, Mario becomes stunned and unable to move after selecting a tile with Bowser behind it.

We'll do something similar by disabling the player from moving when the box with a bear in it is opened.

Let's start by adding a check after the tween that reveals an item is finished. Add this to the onComplete callback in the openBox() method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * 
 * @param {Phaser.Physics.Arcade.Sprite} box 
 */
openBox(box)
{
	// other code...

	this.tweens.add({
		targets: item,
		y: '-=50',
		alpha: 1,
		scale: 1,
		duration: 500,
		onComplete: () => {
			// 👇 add this check
			if (itemType === 0)
			{
				// call handleBearSelected() if true
				this.handleBearSelected()
				return // 👈 and early exit
			}

			if (this.selectedBoxes.length < 2)
			{
				return
			}

			this.checkForMatch()
		}
	})
}

We check to see if itemType is 0 which represents the bear. If true, we call handleBearSelected() and early exit.

Next, let's implement handleBearSelected():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
handleBearSelected()
{
	// get the selected box information
	const { box, item } = this.selectedBoxes.pop()

	// tint the bear red
	item.setTint(0xff0000)

	// set the box to frame 7 (a red box)
	box.setFrame(7)

	// disable the player and any movement
	this.player.active = false
	this.player.setVelocity(0, 0)

	// wait 1 second and then return to normal
	this.time.delayedCall(1000, () => {
		item.setTint(0xffffff)
		box.setFrame(10)
		box.setData('opened', false)

		this.tweens.add({
			targets: item,
			y: '+=50',
			alpha: 0,
			scale: 0,
			duration: 300,
			onComplete: () => {
				this.player.active = true // 👈 re-activate the player
			}
		})
	})
}

First, we call pop() as we did in the previous part to get the last selected box and item. We are using modern JavaScript's Destructuring Syntax on line 4.

It is simply a shorthand for this:

1
2
3
const data = this.selectedBoxes.pop()
const box = data.box
const item = data.item

Then we add a red tint to the bear and change the box to use frame index 7 which is a red box.

Next, we set the player to inactive and stop all movement on lines 13 and 14.

After that, we wait 1 second before restoring everything to normal and tweening the bear out like other items.

We have to add one more thing to stop the player from moving when active is set to false. Add this to updatePlayer():

1
2
3
4
5
6
7
8
9
updatePlayer()
{
	if (!this.player.active)
	{
		return
	}

	// previous code...
}

Now when you open a box with the bear, it will turn red and the player will be unable to move for 1 second. 😎

Checking for Level Completed

You can basically play the entire game now except nothing happens after you find all the matches.

We can do this by keeping a count of how many matches we've found and then compare it against the total matches that can be found in this level.

There are 9 boxes and 1 is the bear which is just there to slow the player down. The remaining 8 make up 4 matching pairs. This means the level is completed when 4 matches are found.

Let's turn that logic into code by first, adding a matchesCount property to the Game Scene:

1
2
3
4
5
6
export default class Game extends Phaser.Scene
{
	// other code...

	matchesCount = 0
}

Notice that we don't need to specify a type using JSDoc because we are setting it to a number.

Next, we want to increment matchesCount each time a match is found. We can do that in checkForMatch() like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
checkForMatch()
{
	// code for no match condition...

	++this.matchesCount // 👈 add this line

	this.time.delayedCall(1000, () => {
		first.box.setFrame(8)
		second.box.setFrame(8)
	})
}

Now we need to check when it is equal to 4 and show a “You Win” message. The player should be disabled as well.

We can do that right after the boxes are changed to use frame index 8 which is a blue box showing that a match has occurred.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
checkForMatch()
{
	// code for no match condition...

	++this.matchesCount

	this.time.delayedCall(1000, () => {
		first.box.setFrame(8)
		second.box.setFrame(8)

		// 👇 check that we have 4 matches
		if (this.matchesCount >= 4)
		{
			// game won

			// 👇 disable and stop player like before
			this.player.active = false
			this.player.setVelocity(0, 0)

			// add a You Win! text 👇
			const { width, height } = this.scale
			this.add.text(width * 0.5, height * 0.5, 'You Win!', {
				fontSize: 48
			})
			.setOrigin(0.5)
		}
	})
}

First, we add a check to see when this.matchesCount is at least 4 on line 12.

When that is true, we disable the player as we did for revealing the bear and then add a “You Win!” text on line 22.

If you would like to make nicer looking text then we recommend taking a look at our Text Styler for Phaser 3 tool. You'll also want to check out this tutorial on loading fonts from Google Fonts here.

Find all the matches and you should see something like this 👇

You Win! - All Matches Found

Next Steps

Our mini Memory Match game is almost done! We can walk around, get stunned, make matches, and be notified when we've completed the level.

The last thing we have left is to add a countdown timer so that there is some challenge. That's what we'll do in part 6!

Be sure to sign up for our newsletter so you don't miss any future Phaser 3 game development tips and techniques!

Drop your email into the box below.

Don't miss any Phaser 3 game development content

Subscribers get exclusive tips & techniques not found on the blog!

Join our newsletter. It's free. We don't spam. Spamming is for jerks.

Phaser 3 memory match memory guide modern javascript

Want tips and techniques more suited for you?


You may also like...


Video Guides


Beginner Guides


Articles Recommended For You

Fix Stretched Image Distortions in Phaser 3 with 9-Slice Scaling

by on

Are you having image distortion problems when scaling to make a button or panel graphic bigger? Multiple versions of the …

5 minute read

Command Pattern to Undo Player Actions

by on

Are you looking for a clean and reusable way to implement undo for player actions? Perhaps you are making a turn-based …

15 minute read

Advanced Logging with the Strategy Pattern

by on

Have you ever tried debugging a problem with your game that only seems to happen in production? The Developer Tools …

7 minute read

State Pattern for Character Movement in Phaser 3

by on

Writing clean and well-organized code is something all game developers aspire to. We want code to be reusable and easy …

7 minute read

Didn't find what you were looking for?


comments powered by Disqus