Are you looking to add more replayability to your game?
Leaderboards are a long-standing feature of single-player games that give players a reason to play multiple times.
Who doesn't want to make it onto the top 10 list of their favorite game?
In this article, we will look at using Firebase and Rex Plugins to implement a leaderboard with no server-side programming for a Phaser 3 game.
The examples are in TypeScript and build on top of the Rocket Mouse game from our free Infinite Runner in Phaser 3 with TypeScript book.
Learn to make an Infinite Runner in Phaser 3 with TypeScript!
Drop your email into the box below to get this free 90+ page book and join our newsletter.
The majority of the leaderboard code will be in a self-contained Scene but we will reference some code from the Rocket Mouse project.
Installing Rex Plugins
There are several ways to install
phaser3-rex-plugins. We will take the
npm approach and import just the
First, run this command to install the plugin to your project:
npm install phaser3-rex-plugins
Set Up Firebase Project
Create a Firebase account and project that will hold the leaderboard.
Head over to https://firebase.google.com to do that.
If you already have a Firebase project then you don't need to create a new one.
Create a web app in your project from the Project Overview section. Firebase will ask for a project name and then give you some code to add to your game.
We will use the CDN approach in this article but you can also install Firebase as an
npm package and import it.
script tags to your
The last thing we need is to initialize Firebase and we will do that in a
Create Leaderboard Scene
Let's start by creating an empty Scene with Firebase initialization at the top:
Most of the code here is given to you by the Firebase dashboard when you create a new project. You can also find it in Settings > Your apps.
Make sure you include the Firebase config values for your project on lines 8 - 14.
declare const firebase: any to let TypeScript know that a global variable called
firebase should exist. This is the case because we are loading Firebase from the CDN. You won't need this if you are importing Firebase as a module.
Then we have a basic Scene that is given a key defined in the
SceneKeys enum. It is from the Rocket Mouse project and looks like this:
You can also just use a string literal.
Create Rex Firebase Leaderboard
Let's import the
LeaderBoard class from
phaser3-rex-plugins at the top of the
Leaderboard Scene like this:
Next, we will create a
LeaderBoard instance and store it in a class property in the
Notice that we are using the type
any for the
leaderboard property on line 5. This is a simple way to work around the lack of official support for TypeScript.
You can also create an
interface based on the plugin docs.
We are expecting a
data argument to be given with a
score property. It will be used later when we go to save a score.
Then on line 12, we use the key
'leaderboard' for the
root property. This will be the name of Firestore collection that stores each entry.
Lastly, we are using placeholder values to set the user on lines 16 - 19. Each of your players should have a different
One way is to use Firebase Auth to create and manage user accounts. Another way is to simply create a UUID and store it in a browser cookie. We won't be covering user accounts in this article.
You might run into an error that says
regenerator-runtime is not defined. It is talking about this library.
That can be fixed by installing it to your project with this command:
npm install regenerator-runtime
Then import it in the
You'll need to enable Firestore from the Firebase Dashboard before leaderboard data can be saved or retrieved.
Go to the Database section in Firebase and click the enable Firestore button.
You'll go through a wizard that asks about location and security. Select Test Mode for security. This will let you continue working on the leaderboard without having to figure out the proper security rules right now.
Save and Display Scores
We've done a lot of set-up so far and now we are ready to use the leaderboard.
Recall that we are expecting a score to be given in the
init() hook. Let's store that value as a class property so that we can use it in the
Next, we can use
this.newScore to save it to Firebase and then retrieve all available scores in
Notice we are using
async to modify the
create() method. This lets us use the
async/await feature of TypeScript for more readable code when dealing with Promises.
The score provided to the
init() hook is used on line 4 to save it to the database.
Then we retrieve the first page of scores and store it in the
Next, we will display the top 5 scores instead of just logging them to the console:
There's a bit of code here but it is all fairly simple.
First, we create a translucent backing that the 5 scores will sit on top of.
Then, we use a
for loop that displays a rank number on line 16. If there is a score for that rank we display the name and score.
Lastly, we increment
75 so that the next row begins under the previous row.
Quick tip: we used the Text Styler tool to design the rank number text.
It will look something like this:
Using the Leaderboard Scene
This section will differ somewhat depending on your project. We will be assuming the Rocket Mouse project mentioned earlier.
We want to run the
Leaderboard Scene when the player has died. That can be found in the
handleOverlapLaser method in the
This method is called when Rocket Mouse hits a laser obstacle and gets killed.
We run the
Leaderboard Scene on line 13 and pass in the current score.
Notice that we check that the
Leaderboard Scene is not already running before running it. An overlap can be triggered multiple times and we only want the Scene to run once.
In Rocket Mouse, the
GameOver Scene is also run so we can adjust the
y value of the message to be under the leaderboard like this:
The key change is that we use
height * 0.9 on line 6 instead of the original
height * 0.5.
Lastly, remember to stop the
Leaderboard Scene when the game is restarted like this:
You now have a global leaderboard to let your players compete with each other for high score!
The leaderboard plugin has more features that you can find here. We are just showing 5 scores but you can add paging to show more.
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.