Creating a Pong Clone in Phaser.JS (Part 3)

Andrew Lloyd
Nov 29, 2020 · 9 min read

Continuing on from Part 1 and Part 2 , Part 3 will be focused on:

  • Adding and detecting scores
  • Indicating which side a player starts on via colours
  • Serving the ball from a player perspective
  • Serving the ball from beginning of the game
  • Serving the ball once scored against
  • Game over condition

Referring to the user stories for the Pong hackathon I find it logical as a developer to group sets of core requirement user stories together to tackle in a logical way:

As a user, I can see that if a ball misses a paddle the opposing side will get a point

As a user, If someone scores 7 points they will will win the game

As a user, the court will appear and an Indication as of which side I am on will be shown

As a user, I will start with the ball, to serve I shall press either the left or right arrow key to serve based on court position

As a user, after I serve I will see the ball travel across the court

I’m going to first work on implementing the scores and having them display to tackle the requirement for a score and also to indicate which player is which to and end user:

Adding the scores

The first thing I want to do is to add a visual representation of the score to the game view.

There are two primary ways to include scores in Phaser, either via Text or Bitmap. Text is the simpler way as bitmap relies on having a texture file as well as an XML or JSON file to parse the character positions. For this example I will use the text method.

First declare some variables to hold our text score for Player 1 and Player 2:

let score1_text;

In the create method we can add a text object to add our two scores to the game world.

score1_text = this.add.text(128, 10, “0”, {
font: “64px Gabriella”,

The fourth property is an object that you can use to declare your font, fill color and alignment. For now I have set the colors to be ##FF000 or red and #0000FF for blue.

For the positioning the scores will be placed at 128 and 672 in the X axis and 10 in the Y axis.

The result looks like this:

Scoring Goals

The scores don’t do anything right now, and they must score whenever one or the other player misses the ball, so we can declare two variables to hold both players’ scores:

let score1;

And set the scores in the create() function:

//set scores

In the update() function we can set score1_text and score2_text to equal our score values:

//setting score text to be value of our scores

And then we can add some conditional logic within our update() to check if the ball has collided with either the left or right side of the board:

//check to see if the ball collides with left or right
if (ball.body.blocked.left) {

If the left side is hit by the ball player 2’s score will increase, and if the right side is hit player 1’s score will increase:

The result should look like this:

I made a slight modification to the ball in this instance with the following line:

ball.setScale(1.5, 1.5);

As we can see the score is increasing on both sides, however we are lacking a reset function and it can be somewhat tricky right now to score past the ultra defensive CPU. We also need a way of addressing the identity of the player so it is clear to know which side is which.

//draw player respective text

Resulting in this:

Now players will definitely have an indication of who’s who on the field!

Serving the ball

Right now the ball just kind of randomly spawns and moves from the center point, we want to be able to serve the ball as per the requirements the user should press the right key to serve it. There are many ways to tackle this, the simplest of which being, placing the ball statically and using the player bat to “serve”

I set up a function called resetSceneWhenP1Scores()

//this function resets the playfield if P1 scores

The logic basically resets the position of both paddles, the ball and sets the players’ velocity to 0 upon scoring.

The function can be called in the conditional block checking if the ball has collided with the right side:

} else if (ball.body.blocked.right) {

We end up with a result that looks like this:

Great the scene is set up for the next round! We can duplicate this logic by recreating the function for when Player2 scores, changing the position of the ball to where player 1 is:

//this function resets the playfield if P2 scores

however at this stage there is a problem, if player 1 scores there is no mechanism to stop player 1 charging over to player 2's side and stealing their launch, and with a human player 2 vice versa. As player 2 (CPU) only moves following the ball’s velocity this should not be a problem with the CPU. A mechanism should be adds a state that can check if the ball is launched which disables movement for the opposite player. When the ball is launched we can change this state to true, which will enable controls for both sides, until a point is scored and the scene reset which would switch our launched check and our disabled controls back to false.

Let’s start by adding a state at the top of the file:

ball_launched = false;

This should be set to false by default

The following three variables should be created also:

let p1scored = false;

We need to track if the ball launch is with the score at 0–0. The firstLaunch variable will only be used once in this instance. The p1scored and p2scored variables can be used as a quick toggler to check which player scored when the conditional logic is written to check what to do after a reset.

Inside of the update function I created a launch_ball function which has a block of conditional checks nested inside of a primary conditional check

The first if statement checks to see if the ball has not been launched, at the start of a new round this check should always be true. At this point we want to disable the player controls by setting the player’s maxVelocity at this point to 0

const launch_ball = () => {

We call the function directly after declaring it as the first action in Update()


We now need to update our score checker and set the variable to true for the corresponding scorer

if (ball.body.blocked.left) {

Finishing the game

To win the game first we need some win screens to go to.

For for sake of expedience for the hackathon I decided the easiest way to go about managing end game conditions was to going to duplicate the existing WinScreen.js file three times inside the same directory using the following naming conventions:

Cpuwins.js, P1Wins.js, P2wins.js

The first thing to do with CPU wins is to rename the key as each scene inside Phaser has to have a unique key, this one I named cpuwinscreen

import Phaser from “phaser”;

I modified the file by adding another text object with different properties on to colour coordinate the win screen text. I also used a setTimeout function in the update to return to the main menu scene after three seconds. I repeated the same process for the P1 and P2 win screens.

To use the new scenes We must import our scenes into index.js as follows:

import Phaser from “phaser”;

We also need to add the scenes into the scene: array so that Phaser knows how to access and reference them in the scene object.

The next change I made was in the Game.js file. A win condition is needed in the game instance to check for a win at 7 points with a simple equality check and the logic would move the scene on to the winners’ respective screen.

const checkWin = () => {

If I would have had more time to optimise the win screens ideally I would have found a way to pass a value onto one win screen and make the content dynamic to save the amount of repetition of files and code in the project.

When the player or CPU reaches 7 points the results will look as follows with the added logic:

This wraps up part 3 of the technical writeup for PhaserPong. Part 4 will cover:

  • Add a second player game mode
  • More menus and scenes
  • Changes to 2nd player physics and velocity limitations

You can find the progress on the repo for the project here

About the Author

Andrew is a dynamic full-stack developer and passionate learner who is comfortable speaking to clients as well as fellow developers. Eager to use cutting-edge technologies, alongside building long lasting applications and websites.

He is a graduate from Lighthouse Lab’s web development bootcamp, and is a part of the community.

He has learned and implemented various skills including

  • HTML5
  • JavaScript
  • JQuery
  • CSS3
  • MySQL/PostgreSQL
  • Bootstrap
  • MaterialUI
  • React
  • Redux

Prior to attending bootcamp in August 2020 his areas of work have been: administration, lecturing, film production and post-production and customer service across various sectors.

He would love to connect for opportunities and to find a way to offer his skills.

The Startup

Get smarter at building your thing. Join The Startup’s +786K followers.

Sign up for Top 10 Stories

By The Startup

Get smarter at building your thing. Subscribe to receive The Startup's top 10 most read stories — delivered straight into your inbox, once a week. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +786K followers.

Andrew Lloyd

Written by

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +786K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store