JavaScript Pong with p5.js

Photo by James Thomas Thomas on Unsplash

This beginner-level tutorial walks you through building a single-player pong game with the JavaScript library p5.js.

All you need for a pong game is a rectangle, an ellipse, and a little animation. p5.js supplies all of those! With some extra code to make the ball bounce off the walls and the paddle, we can make a single-player pong game.

**If you get stuck at any time, check out the solution code.

Quick intro to p5.js

Open the p5.js editor. You’ll see this code:

function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}

If you’re familiar with JavaScript, you can see that we have two functions here: setup and draw. If you’re not familiar with JavaScript, no worries! Functions are just little packages of code.

At the top of the code, the setup function runs once, at the beginning of the program, and here it just creates a 400x400 canvas for us.

The draw function runs over and over again, animating the screen. By continuously updating the x- and y-coordinates of an object in the draw function, you can animate it.

Important syntax notes: First of all, when we add our own code to these functions, make sure you add it inside the curly braces: { and }, NOT inside the parentheses! On that note, make sure that every function and if statement has both an opening curly brace { and a closing curly brace }. Finally, make sure to end each line in a semi-colon: ;

Changing our background

Our background is currently light grey. If you press the “play” button (shaped like a triangle), you can see it appear:

Let’s change our background. I’m going to make mine black, since I intend to make a neon-colored paddle and ball for my pong game.

You can fill in just one value in the background function between 0 (black) and 255 (white) to create a shade of grey. Here is the code for a black background, importantly placed as the first line of the draw function:

function draw() {
background(0);
}

However, you can also add three values to the background function to use RGB colors (e.g. background(0, 0, 255) for blue). Hex colors are also an option (e.g. background('#0000ff') for the same blue). This color picker provides both RGB and hex values for many colors.

Feel free to get more adventurous than plain black!

The 400x400 canvas is a little limiting, so I’m also going to update the setup function to span over the whole window:

function setup() {
createCanvas(windowWidth, windowHeight);
}

Don’t be alarmed when windowWidth and windowHeight turn pink — it’s just the computer’s way of saying that it knows what you’re talking about.

Now if we refresh, our canvas takes up the whole preview screen!

Adding a ball

Our ball will just be an ellipse whose coordinate points we update over and over again, so that it moves.

We can create a ball on the screen by adding this code at the bottom of our draw function (after the background):

fill(255, 0, 255);
noStroke();
ellipse(100, 100, 50, 50);

The fill function sets the color for the next object, and you’re free to change the RGB values to something other than its current magenta (all values must be between 0 and 255). noStroke ensures that the ball doesn’t have an unsightly outline. The code in the ellipse function places the circle at the point (100, 100) and gives it both a width and height of 50 (making it a circle).

Our 50x50 magenta ball at (100, 100)

However, we’ll be constantly changing the x- and y-coordinates of the ball to animate it, so it would be better to store those in variables. We’ll also being doing some calculations with the width and height (=diameter) of the ball, so it would be nice to store that too.

At the very top of your code, before the setup function, create these variables:

var xBall = Math.floor(Math.random() * 300) + 50;
var yBall = 50;
var diameter = 50;

xBall starts off the ball with a random x-coordinate between 50 and 350. yBall starts off the ball with a default y-coordinate of 50. The diameter is also set to 50.

Now we can update the ellipse in our draw function to read:

ellipse(xBall, yBall, diameter, diameter);

The ball will move to a random location near the top, but everything else should be the same. Now we are prepared to animate our ball!

Making it bounce

First, we need to track the speed at which the ball changes x- and y-coordinates. Add these two variables to your list at the top:

var xBallChange = 5;
var yBallChange = 5;

Now, after you set the background in the draw function, add in these two lines of code to continuously change the ball’s location, incrementing its x- and y-coordinates by the xBallChange and yBallChange values:

xBall += xBallChange;
yBall += yBallChange;

Does your ball move?

Yay! …except it also goes right off the screen.

We need to make the ball detect when it is hitting the walls, using our windowWidth and windowHeight variables, as well as our knowledge of the ball’s diameter.

This code below checks to see if the ball’s x-coordinate is between 0 and windowWidth, and if the ball’s y-coordinate is between 0 and windowHeight. If the coordinates are outside those ranges, the ball has hit a wall. Place this code in your draw function, right after you change the ball’s coordinates:

if (xBall < diameter/2 || 
xBall > windowWidth - 0.5*diameter) {
xBallChange *= -1;
}
if (yBall < diameter/2 ||
yBall > windowHeight - diameter) {
yBallChange *= -1;
}

Because the ball’s x- and y-coordinates are based on its very center, the diameter comes into play in these calculations as well.

When the ball collides with the wall, it can go in the opposite direction if you make the coordinate change go from positive to negative, or vice versa. You can see that xBallChange and yBallChange are multiplied by -1 to achieve this effect. MATH!

Now, your ball should bounce off the walls!

Adding a paddle

The paddle is just a rectangle. But before we get too excited and preemptively add a rectangle to the scene, let’s define some variables for our paddle. Add these to the top of your code, along with the ball-associated variables:

var xPaddle;
var yPaddle;
var paddleWidth = 100;
var paddleHeight = 25;

This allows us to alter the paddle’s x- and y-coordinates from anywhere in the code and prepares us to define a 100x25 paddle.

I would like to define default x- and y-coordinates for the paddle using the built-in windowWidth and windowHeight functions so that I can place the paddle in the middle of the screen, near the bottom. However, I can’t use those built-in variables outside of setup and draw!

Instead, we will need to get creative. I’m going to add another variable to our lengthy list:

var started = false;

Now, when I go down into my draw function, I can check if the game has started yet. If it hasn’t (if started is false), I can use those built-in variables to place my paddle exactly where I want it.

Add this code to the bottom of your draw function:

if (!started) {
xPaddle = windowWidth / 2;
yPaddle = windowHeight - 100;
started = true;
}

If the game has not yet started, the paddle is placed at the middle of the window about 100px above the bottom of the screen. Since started is then declared true, this code never runs again.

Add the following code to your draw function to create the paddle. Make sure it occurs AFTER the if statement above!

fill(0, 255, 255);
noStroke();
rect(xPaddle, yPaddle, paddleWidth, paddleHeight);

This code draws a paddle using the variables we pre-defined above. As always, feel to change the RGB color in fill.

Now test it out! Does the paddle appear?

Controlling the paddle with the arrow keys

Obviously, the game is boring if the paddle can’t move. To make the paddle controlled by the right and left arrow keys, we simply add a third function below draw.

The keyPressed function will allow us to adjust the paddle’s x-coordinates by incrementing or decrementing the xPaddle variable. Add this code to the bottom of your program, after the draw function ends:

function keyPressed() {
if (keyCode === LEFT_ARROW) {
xPaddle -= 50;
} else if (keyCode === RIGHT_ARROW) {
xPaddle += 50;
}
}

Now you should be able to control your paddle with the right and left arrow keys!

Detecting collision with the paddle

However, the ball totally ignores the paddle and just sails right through it! That’s because we need to be checking if the ball is colliding with the paddle.

Specifically, we need to check if the ball’s x-coordinate is between the right and left ends of the paddle, and if its y-coordinate hits the top of the paddle.

That’s what this code below does. Paste it right after the code that makes the ball bounce off the walls in the draw function:

if ((xBall > xPaddle &&
xBall < xPaddle + paddleWidth) &&
(yBall + (diameter/2) >= yPaddle)) {
xBallChange *= -1;
yBallChange *= -1;
}

Notice how again, we make the ball go in the opposite direction by having it change from a positive to negative direction (or vice versa — multiplying by -1 will make the ball do the opposite of whatever it was doing).

Now your ball should bounce off the paddle!

Keeping score

So far, you have a fully functional pong game. Congratulations! However, to make it even fancier, we can add a mechanism to keep score.

First, let’s add yet another variable to our list:

var score = 0;

Every time the ball collides with the paddle, we can increase the score by one. Find the if statement in your draw function that detects the ball-paddle collision. Add this line of code inside it:

score++;

The ++ is a shorthand that means “increase by one!”

Finally, let’s display the score on the screen. At the bottom of your draw function, add in the following code:

fill(0, 255, 255);
textSize(24);
text("Score: " + score, 10, 25);

Now the program should award you points whenever you successfully bounce the ball!

Congratulations on building a single-player pong game!

Extensions

Yearning for additional p5.js challenges? Try these out…

  1. Change the font, color, and position of the text using the text documentation.
  2. Change the color of the ball or paddle.
  3. Make the ball change colors when it bounces. (Hint: make an array of colors, and then randomly select a color each time it bounces.)
  4. Make the background a gradient. (Hint: see the setGradient function or find the part of the sunset tutorial that shows you how to make a gradient background.)
  5. Detect when the ball hits the ground. When it does, stop the ball and have it print “Game Over” at the top. (Hint: you’ll want to check if the ball’s y-coordinate has surpassed the windowHeight.)

For more p5.js, I have also written an Instagram Filter tutorial and a Sunset Scene tutorial. The documentation is also a wonderful resource. If you like books about code, Getting Started with p5.js is the top choice. Finally, if you’re in NYC or LA, check out CC Fest!