« Back to Blog

Phaser Platformer Series: 1 Introduction

posted on 2 March 2021

This series of tutorials will go through the standard tropes of a platform game in Phaser 3. With each tutorial, we will add something new, coins, baddies, shells, ladders etc. By the end of the series, you’ll have the tools to make a complete HTML5 platformer that runs on desktop AND mobile browsers. The two biggies with this series are:

  • Low barrier to entry – no webpack, no gulp, no es6 modules. I may well bring in some of these later, but for these tutorials, it’s all about basics and core mechanics.
  • Works on all devices –  So many HTML5 games are desktop only and require a keyboard. These will work on mobile!

These tutorials assume that you know a little bit of javascript and that you’ve been through the phaser Getting Started and Making your first game tutorials. It picks up right where they left off and follow their low barrier to entry style. We’re deliberately trying to keep it simple for now. No build tools, no ES6 and the most minimal setup possible. We’ll be using Phaser 3.5, which is out recently and a very stable release that should be relevant for some time.

In this tutorial we’ll be making this:

See the Pen
Phaser Platformer: 1 Introduction
by Digitherium (@digitherium)
on CodePen.

You can view all the code on codepen and download the source on github.

We’ll be using the arcade physics system which Phaser describes as ‘simple and light-weight, perfect for mobile browsers’. The rub is, to keep it simple and lightweight, all its collisions are based on rectangles. That means if your hero character is not a perfect rectangle, then when they collect something or jump on a baddie, it’s not exact. If you look back at the previously mentioned official Phaser platform examples you’ll see what I mean. When you collect a star it’s an invisible bounding box around the character that hits it. This means that the star is collected a little bit before the two sprites appear to meet. There are more complex physics systems available which allow you to get around this problem and have more complicated collisions, but they don’t run so well on mobile. If we want it to work on mobile (which I really do) then it’s price we’re just going to have to pay.

With that in mind, the ‘squareness’ of the physics is a constraint we’re going to run with. We’ll be using 32px squares for the sprites (this idea is stolen from the excellent lessmilk.com). This should allow us to just concentrate on the game mechanics for now. We’ll come back to the sprites later.

As a very quick recap, Phaser games consist of three main functions:

  • preload – where we load all our game assets
  • create – where we set everything up and place our game objects
  • update – responsible for updating and redrawing game objects. It’s called every frame, so if the game was running at 60 frames per second this function would run 60 times a second. You will often here it referred to as the ‘game loop’, as it called on a loop and is where the guts of the game and logic live.

Let’s go ahead and simplify the sprites. No more animations and no more Mr onion head alien. We do this by changing the official Phaser examples preload function to this:

function preload() {
        this.load.image('ground', 'platform.png');
        this.load.image('coin', 'coin.png');
        this.load.image('hero', 'hero.png');

First thing we do there is set the base URL where our game assets are loaded from, in our case the folder assets. If you are looking at the code on codepen you’ll see it point to a folder I set up on this site.

We’re calling our dude, ‘hero‘. Our hero is going to collect coins not stars, so I renamed them too. I also removed any code that reference animations as I’m using an image and not a sprite sheet.

And that’s that. We’ve taken the lovely animated Phaser example and replaced the sprites with boring squares. It may seem like we’re going backwards but it will all start to make sense in the next tutorial with ‘game feel’ and inertia.

view all the code on codepen
download the source on github.