Here's the full index of all the articles in this series for context:
- Part 1: Introduction to gaming concepts and the Phaser library
- Part 2: Evaluating networking protocols for realtime apps
- Part 3: Implementing the server-side code to keep all players in sync
- Part 4: Finishing up the client-side code to render the game
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
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
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 and subscribe to the channels. Add the following code, right below the variable declarations in
One of the key things to note here is the
gameRoom.presence.enter(myNickname); method. Ably uses a concept called 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:
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-over events on the
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:
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
Let's define these methods next. Please note that these methods are part of 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.
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.
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.
This class extends
Phaser.GameObjects.Sprite and plays the
explode animation that we defined in the
create() method of our
GameScene class in the
Now let's get back to
script.js and define one last method within the
GameScene class, the
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.
views folder, add four files:
public folder, add three files:
gameRoomFull.html is displayed when anyone tries to join the game after the preset maximum number of players have already joined.
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.
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.
gameover.html page is shown if all the players in the game die. This page just shows the nicknames of the top two scorers.
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 or Glitch. 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 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 on this project.
As always, if you have any questions, please feel free to reach out to me on Twitter @Srushtika. My DMs are open :)