Learning to LÖVE: We’re Gonna Make Pong

This entry is part 2 of 2 in the series Learning to Love

This is Lesson 2 in my series on getting start making games Learning to LoveIf you need to get your computer setup for making games with the LOVE framework, see Lesson 1:  Learning to LÖVE: Getting Started with LÖVE.

At the end of the first Lesson we created a blank project in a new folder with a single empty file called main.lua  in it. This was the minimum setup for LOVE to run a game, but it just opened a empty window with that blank file. We’ll fill that file up with our first game now.

We’re going to make pong!

This is the actual version of PONG we’re going to be making today. The paddle on the right is the player, controlled by the up and down arrows. The paddle on the left is an AI player that tracks the ball, trying to bounce it back at us. The score will be kept at the top of the screen, and the ball will increase in speed as the play continues, getting trickier and trickier to follow.

If you’ve never programmed before, don’t worry. We’ll walk through every step one at a time. You’ll be able to learn along the way.

You build anything by breaking it down into little steps. Any game, even one as tiny as PONG, is too big to make all at once. Instead, we’ll start with a very simple thing, and we’ll keep adding pieces until we have our PONG game. Here are the steps we’ll be taking to build the game.

  1. Draw a simple rectangle on the screen. This will be our ball.
  2. Make the ball bounce around the screen
  3. Make the player and AI paddles on the sides of the screen, controlled by the computer and the player.
  4. Make the ball bounce off the paddles and not the sides of the screen.
  5. Add a score counter and we’re done.

Let’s jump into step one!

Step 1: Drawing Simple Boxes with LOVE

Let’s start learning some basics. We’re going to draw a square! Enter these simple lines and run your game.

(If you need a refresher about how to run the game, which we covered in Lesson 1, just press that big play button in the top-left toolbar of your Atom editor!)

This is your very first actual LOVE program, so lets break down what it did. If you ran it, you’d see this screen (I’ve drawn on the screen to explain what’s happening).

We decided where to draw the box by naming two numbers BALL_X  and BALL_Y . We decided how large to draw it by naming two numbers BALL_WIDTH  and BALL_HEIGHT .

We can tell LOVE to draw a rectangle for us using the love.graphics.rectangle()  command. (The words “command” and “function” are largely interchangeable) We use the numbers we named (those are called “variables”) to tell the command how we want to draw the rectangle.

Games draw to the screen very fast. Usually the screen is drawn 30 to 60 times every single second. Your game is no different. LOVE needs to know what code in your program draws everything so that it can re-run it every single frame.

Hey, Wait A Minute… Why “30 to 60” instead of an Exact Number?
Good question, intrepid reader!

Your game has a lot of work to do moving things around and handling input and doing all the things to make your game work. This draw function is called in between that work, when the game has a small break to draw()  everything to the screen. If the computer can’t draw fast enough, draw() will be called less often.

That’s how we get frame-rates (or FPS) in games!

We wrap our drawing code into our own function called “ love.draw() ” which LOVE will call every time it needs to draw to the screen. Functions are commands that do a certain job.

love.graphics.setColor()  is a function to tell LOVE what color we want to draw things to the screen with. We use love.graphics.setColor(255, 255, 255) to set the color to white.

love.graphics.rectangle()  is a function we use and love.draw()  is a function we create.

Of course, that’s much too big for a PONG ball, so make it a bit smaller before moving on. Feel free to play around with all four numbers to see how it draws different rectangles on the screen before continuing on to the next part of the lesson.

Step 2: Move the rectangle with a velocity

Now that we can draw a simple square, lets start turning this into our pong game. We’re going to start it moving.

Now, we’ll move it. The love.update()  function is the next command we’ll create for LOVE, a lot like love.draw()  and also called many times a second. Instead of drawing to the screen, this function is called when LOVE wants us to update all the data in our game. This is when we’ll move characters who are moving on the screen, change colors to make lights flash, and check if lots of moving objects hit each other.

If we change the value of the BALL_X variable the square will move along the screen. Run the game with this added to your mail.lua file.

You’ll see the ball moving quickly across the screen. Probably too fast.

Every time LOVE calls our love.update function we move the ball by 25 pixels. Unfortunately, because this could happen any number of times a second, we don’t actually know how maybe times this happens or fast it will move. We can fix that!

Let’s say we want the ball to move 25 pixels per second. The function is passed an important value we can use: the amount of time that passed since the last time it was called. We can use this to figure out exactly how far to move the ball every frame. We’ll go ahead and move it in two directions, as well, by adding a line to change BALL_Y the same way.

All we’ve changed is multiplying the movement by this value we’re given, and now our ball will move at a steady pace. If you change the value 25 you’ll make the ball move faster or slower.

Bound the rectangle on the screen top/bottom

The first thing you might notice is the ball just flying right off the edge of the screen! That’s not going to make a very good game of pong. Let’s start to keep it inside the game area.

This version of our update function moves the ball in the down-right direction. We’ll make the ball bounce against the bottom edge. After we’ve moved the ball we want to ask, “Has it reached the edge of the screen?” and, if so, we want to make it bounce.

Now, because we need to be able to change the direction of the ball we need the direction its moving in to be a variable instead of just a number. We’ll make separate variables for the movement along the X axis and Y axis.

How do we change the direction the ball is moving in? We just make the number negative. If BALL_VX or BALL_VY are -100 instead of 100 then we’ll be subtracting from BALL_X and BALL_Y every time our update function is called.

With the ball moving based on our new variables, we can add a few lines to check if the ball has moved past the left side of the screen, because that’s the direction the ball starts moving.

…of course, we want to make it bounce on both sides…

and we want to bounce on the top and bottom of the screen, as well!

 If you need to catch up, here’s the complete main.lua code you should have at the end of Step 2

Step 3: Adding both Computer and Player Controlled Paddles

We’ve got the ball bouncing around the screen, but we need to do something with it, so we’ve got to create the Player and Computer paddles. We’ll be giving the player the ability to move the paddle on the right side of the screen up and down. The computer will move the other paddle to track the ball as it bounces around the screen.

First, we’ll draw the paddles. This works just like drawing the ball. Let’s add some more variables at the top of our code to track the placement and speed of the paddles.

And we add two lines to love.draw()  to put the paddles on the screen.

They’ll try to hit the ball with it to keep it from hitting the edge. So, we’ve only got two directions of control to implement and we’ll start with wiring up the down button.

The love.keyboard.isDown() function will tell you if a button is being held down by the player. Ask it if the player is holding the down button and, if they are, move the paddling down. We use the same trick of multiplying by dt to ensure a smooth speed.

…and we’ll do the same thing for the up button to move the right-side paddle up.

If you need the code as it should appear at the end of Step 3, here it is:

Step 4: Bouncing the ball off the paddle

Now comes the really important bit: making the ball bounce off both of our moving paddles. Bouncing on the screen edges was pretty easy, relatively, because those are fixed and stretch the full size of the screen. The paddles are smaller and move and we have to let the ball bounce on them but pass to the edge if they miss.

Let’s look at some measurements we can use in a typical game of PONG. We’ll focus on the player paddle on the right, first.

BY: How far is the ball from the top?

PY: How far is the paddle from the top?

BX and PY: How far are they from the left side?

25: The size of the ball

150: The height of the paddle

Now, we just ask three questions to find out if the ball hits this paddle:

Is the ball far enough to the right to touch the paddle?

Is the ball below the top of the paddle?

Is the ball above the bottom of the paddle?

Here’s how our three questions translate into a simple if  statement to determine the collision:

Bouncing on the left paddle is almost the same.

The ball still bounces against all the edges of the screen, but now it bounces against the paddles as well. Of course, the point of the game is that you have to hit the ball with the paddle, so what should happen when the ball touches the left or right edges? It shouldn’t bounce. Instead, it should pass through the edge and then re-appear in the center of the screen for a new round to start.

Here’s how we’re currently bouncing the ball on the sides of the screen:

We want to allow the ball to pass a little beyond the edges, so we want to change the values 800 and 0. And, we’ll replace the line that bounces with a line of code to move the ball back to the start.

This step was a bit simpler than the previous ones. That’s it. It wasn’t much to add, but here’s the complete code at this end of this step:

Step 5: Keeping Score

Our last step is adding a little bit of polish by keeping score for the two players. Just like the original PONG we’ll put the scores at the top of the screen and they’ll count each time a player scores a point.

Before we keep score we need to add two new variables to keep them in. The scores will start at 0, of course, so add them to the top of your file with the other scores:

Right now we just reset the ball when it passes beyond one of the side edges:

So, we’ll add some lines here, but we need to check which side the ball went through, because now it matters. We need to know which player to award a point to.

And, the very last step in making our game, is adding just a few more lines to the love.draw()  function to use a new LOVE function called love.graphics.printf() . This lets us draw text on the screen. Our variables LEFT_SCORE  and RIGHT_SCORE  are numbers, but we have to give printf()  text and we convert them with the tostring()  function, which you can see in the code here:

Wow.

You just made a whole game. I’m impressed with you! Give yourself a pat on the back. Call someone over to your computer to show it off! Tell your friends about it!

You should feel good about taking this first step. You are a game developer.

The Learning to LOVE series will continue. I hope you enjoyed it so far, and if you want to learn more you should subscribe to my newsletter for all things gamedev related. The newsletter is from my little game studio Stonebird Games, but its a big focus on the making of games. Sign up for new updates about Learning to LOVE and my other game dev projects!

Complete Source

Here’s the complete game running! You made this! If you need it, the complete code is below. You can mess around with it, and I encourage you to do so. Try tweaking the BALL_START_SPEED  or the height of the paddles. Try making them shorter for a challenge? Maybe see what happens if the ball gets even faster with every bounce off the paddles.

Play around, learn more, come back for more LOVE lessons in the future!

 

Series Navigation<< Learning to LÖVE: Getting Started with LÖVE (on Windows)

Leave a Reply

Your email address will not be published. Required fields are marked *