This is the fifth (and final!) post in a series of blog posts about creating modular worlds with tilemaps in the Phaser 3 game engine. In this edition, we’ll step up our Matter.js knowledge and create a little puzzle-y platformer:

Pushing crates around to avoid spikes and hopping over seesaw platforms

If you haven’t checked out the previous posts in the series, here are the links:

Before we dive in, all the source code and assets that go along with this post can be found in this repository. These tutorials use the latest version of Phaser (v3.16.2) and Tiled (v1.2.2) as of 02/26/19. Some pairings of older versions of Phaser and Tiled don’t get along well, so I recommend using these two version.

Intended Audience

This post will make the most sense if you have some experience with JavaScript (classes, arrow functions & modules), Phaser and the Tiled map editor. If you don’t, you might want to start at the beginning of the series, or continue reading and keep Google, the Phaser tutorial and the Phaser examples & documentation handy.

Overview

In the last post, we got acquainted with the Matter.js physics engine and played with dropping bouncy emoji around a scene. Now we’re going to build on that Matter knowledge and step through building a 2D platformer. We’ll learn how collisions work in Matter, get familiar with a plugin that will allow us to neatly watch for collisions in Phaser and then get into the core of the platformer.

Collisions in Matter

The crux of what we are going to do revolves around handling Matter collisions. If we want to use physics in a game, we need to be able to respond when certain objects collide with one another, e.g. like a player character stepping on a trap door. Since Phaser’s implementation of Matter is a thin wrapper around the underlying library, it’s worth revisiting our vanilla Matter example from last time to learn about collision detection in Matter. If you are impatient, you could jump ahead two sections to get straight to the platformer. But if you like to understand how something really works — which I think will pay off in the long run — then stick with me here.

Here’s what we’re aiming for in this section:

The shapes light up when they collide with each other, and they turn purple when they hit the floor.

Here’s a CodeSandbox starter project that matches what we did last time. I’d recommend opening that up and coding along. There’s a comment towards the bottom of the file that shows you where to start coding. The setup is the same as last time:

We create a renderer and engine. We create some different shaped bodies that will bounce around the world. We add some static bodies — bodies that are unable to move or rotate — to act as obstacles. We add everything to the world and kick off the renderer & engine loops.

To start listening for collisions, we need to add a new module alias at the top of the file, Events :

Events allows us to subscribe to event emitters in Matter. The two events we will play with in this demo are collisionStart and collisionEnd . (See the documentation for other engine events.)

On each tick of the engine’s loop, Matter keeps track of all pairs of objects that just started colliding ( collisionStart ), have continued colliding for multiple ticks ( collisionActive ) or just finished colliding ( collisionEnd ). The events have the same structure. Each provides a single argument — an object — with a pairs property that is an array of all pairs of Matter bodies that were colliding. Each pair has bodyA and bodyB properties that give us access to which two bodies collided. Inside of our event listener, we can loop over all the pairs, look for collisions we care about and do something. Let's start by making anything that collides slightly transparent (using the body's render property):

Now we can extend our collisionStart to have some conditional logic based on which bodies are colliding:

In the first conditional, we check if one of the bodies is the floor, then we adjust the color of the other body to match the floor color. In the second conditional, we check if the circle hit the floor, and if so, kill it. With those basics, we can do a lot in a game world — like checking if the player hit a button, or if any object fell into lava.