Building a realtime multiplayer browser game in less than a day - Part 4/4
Tags: javascript, gamedev, architecture, tutorial
Published: 2020-06-12 10:04:20

Hello, and welcome to the final part of this article series where we are looking at the step-by-step implementation of a realtime multiplayer game of space invaders with [Phaser3](https://phaser.io/) and [Ably Realtime](https://ably.com/). 🚀

---

Here's the full index of all the articles in this series for context:

- Part 1: [Introduction to gaming concepts and the Phaser library](https://dev.to/srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-14pm)
- Part 2: [Evaluating networking protocols for realtime apps](https://dev.to/ablydev/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-1p1l)
- Part 3: [Implementing the server-side code to keep all players in sync](https://dev.to/ablydev/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-4bbm)
- Part 4: [Finishing up the client-side code to render the game](https://dev.to/ablydev/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-3d2j)

---

In this article, we'll finish up the client-side code to render the game and  also add the home and leaderboard screens for our game.

If you recall, in the first article we added the `GameScene` class and defined the `preload()` method in it. We also added the `create()` and `update()` methods but didn't define them fully.

Let's start by adding some variables that we'll use later. Add these at the top of `script.js` (which should be inside the `public` folder:

{% gist https://gist.github.com/Srushtika/43651d7fba2ade4880c678bebc5d7e6d %}

Make sure to update the `BASE_SERVER_URL` with your server's URL. If you have hosted the game locally, this URL would be your localhost with the port number. 

Next, we'll have the client connect to [Ably](https://ably.com/) and subscribe to the channels. To do that, go to the [Ably dashboard](https://ably.com/dashboard) and add the following code, right below the variable declarations in `script.js`

{% gist https://gist.github.com/Srushtika/418952ac41bf19d17ab3ec37eb52399e %}

One of the key things to note here is the `gameRoom.presence.enter(myNickname);` method. Ably uses a concept called [Presence](https://ably.com/documentation/core-features/presence) to determine connected clients in an app. It fires an event whenever a new client joins, or when an existing client leaves or updates their data.

Notice that this is where we instantiate a new game object with the `GameScene` that we started defining in the first part. So, let's resume that. The `create()` method of the class should now look as follows:

{% gist https://gist.github.com/Srushtika/243ca48379cadf920f906b81cf907e4a %}

We had already defined the `this.anims.create()`method in the first article. Just above that, we add and initialize a few variables. We then subscribe to the `game-state` and `game-over` events on the `gameRoom` channels.

When we get a `game-state` update, we update the client-side variables as per the latest info from the server. 

When we get a `game-over` update, we store the leaderboard info in local storage. We then unsubscribe the client from all channels and simply switch to a new webpage because either someone won or all players became dead.

Let's look at the `update()` method next:

{% gist https://gist.github.com/Srushtika/9acbef3fd362303573a29b08c55b4af5 %}

In the update method, we move the existing game objects in accordance with the latest info. We also create new avatars for the newly joined players, and kill avatars of any player that has died by calling the `explodeAndKill()` method. We also update the score, and flash the join and leave updates in the `<p>` elements outside the game canvas.

If the server says a player just died, we call the `explodeAndKill()` method that will perform the explode animation and destroy that player's avatar.

A bullet gets fired once for every five game ticks. So the server either sends a blank or a bullet object, with a unique ID and a position that matches the ship's y-axis level. If it hasn't already been shot, its `toLaunch` flag will be true. So we check that and create a new bullet by calling the `createBullet()` method. Otherwise, we'll move an existing one.

We also check if the player has pressed the left of right keys via the `publishMyInput()` method. 

Let's define these methods next. Please note that these methods are part of the `GameScene` class.

{% gist https://gist.github.com/Srushtika/0c758dc6d131c5f0f6db108227ed2e9d %}

In the `createBullet()` method, we add a new bullet object according to the latest position of the ship and add this bullet to the `visibleBullets` associative array that's part of the `GameScene` class. We also add an overlap method for the current player's avatar and every bullet we add. This method will keep track of the overlap of the two game objects overlapping. When that occurs, Phaser will invoke a callback method, which in this case is  `publishMyDeathNews()`. We'll define that later.

In the `publishMyInput()` method, we check if the left or right key was pressed, and if yes, publish that info to Ably. It's worth noting here that we never move the avatars directly as a result of user input. We publish this info to the server, which in turn fans it out to all the players, including the current player, resulting in a perfect state synchronisation. This communication happens so fast that it doesn't really feel any different to the user playing the game.

In the `explodeAndKill()` method,  we create a new instance of the `Explosion` class. We haven't defined that yet, so let's take a brief detour from the `script.js` file that we've been working on, to add it. Create a new file in the `public` folder, call it `explosion.js` and paste the following code in it.

{% gist https://gist.github.com/Srushtika/9cf0a0ca43f9bc9410fb336fa789e4e3 %}

This class extends `Phaser.GameObjects.Sprite` and plays the `explode` animation that we defined in the `create()` method of our `GameScene` class in the `script.js` file.

Now let's get back to `script.js` and define one last method within the `GameScene` class, the `publishMyDeathNews()`:

{% gist https://gist.github.com/Srushtika/700d44c31f16ba14dbf2bc7def2f90d9 %}

This method is invoked when a bullet object overlaps with the current player's avatar, meaning the player has been shot. When that happens, we simply publish this information to the server so it can update the game state accordingly and fan this information out to all the clients, including the current player, so they can update their respective game states accordingly.

We are all done with the game implementation. We just have to add the home and leaderboard pages to make the game more complete.

###Adding the home and leaderboard pages

In the `views` folder, add four files:

- `gameRoomFull.html`

{% gist https://gist.github.com/Srushtika/da4793674dba9668748637c100b4b509 %}

- `intro.html`

{% gist https://gist.github.com/Srushtika/f0198c3b7d673daaa98c4abe444ab228 %}

- `winner.html`

{% gist https://gist.github.com/Srushtika/af5f37f5d649333675f7846269835aef %}

- `gameover.html`

{% gist https://gist.github.com/Srushtika/bebcd81bfc67e315b45d26e5145246ea %}

![Homepage screen](https://dev-to-uploads.s3.amazonaws.com/i/wycswh2bama6t71y2zvv.png)

![Winner screen](https://dev-to-uploads.s3.amazonaws.com/i/ybw1xwmhcrsl5amily78.png)

In the `public` folder, add three files:

- `nickname.js`

{% gist https://gist.github.com/Srushtika/34b522d3b94e0560b936c1d6631dc0cc %}

- `winner.js`

{% gist https://gist.github.com/Srushtika/03d39d726f7388753c9f93cfbf1488e9 %}

- `gameover.js`

{% gist https://gist.github.com/Srushtika/a7e7d71b345586d7b85de6435344654e %}

The `gameRoomFull.html` is displayed when anyone tries to join the game after the preset maximum number of players have already joined. 

The `intro.html` file gives the user a simple text box to enter their nickname. This info is used to flash join/leave updates and also show the info in the leaderboard.

The `winner.html` page is shown if the game ends due to a player winning the game. This page will then display their nickname as the winner and also show the first and second runners up.

The `gameover.html` page is shown if all the players in the game die. This page just shows the nicknames of the top two scorers.

The related JavaScript files simply retrieve the info from the local storage and set it in the relevant HTML elements.

---

That's it, we've now full implemented the game 🙌🏽🙌🏽🙌🏽

Let's go ahead and run it. We first need to run the server, so from your command line, navigate to the folder where the server file is and run `node server.js`. This will start the server. Now, open three browser windows and keep them side-by-side. Hit the base URL of your server from all the three windows. You should see the `intro.html` page being served asking for a nickname. Give each player a nickname and enter. After the third player enters, the ship starts with the bullets going off. Make sure to control each player to avoid getting killed.

If it's running as expected, you can host this game using a free hosting service such as [Heroku](https://heroku.com) or [Glitch](https://glitch.com/). This will allow you to access the game via a public URL letting you play the game for real with your friends on other computers.

A [separate release](https://github.com/Srushtika/realtime-multiplayer-space-invaders/releases/tag/v1.0.1) relevant to this tutorial is available on GitHub if you'd like to check it out.

You can also [follow the Github project for latest developments](https://github.com/Srushtika/realtime-multiplayer-space-invaders) on this project.

---

As always, if you have any questions, please feel free to reach out to me on Twitter [@Srushtika](https://twitter.com/Srushtika/). My DMs are open :)