Building Pong in C++

written on February 8, 2019

categories: game-dev

tags: C++, SFML

So yesterday I started making Pong in C++, using SFML. (here's the repo link btw)

I've recently discovered SFML thanks to a C++ class in my university, and I thought I could try and make some basic games with it - and what's a better start than Pong! It's simple yet it's complex enough to convince me if SFML can help me make games easily or not (so far I'm leaning towards the former).

I want to document my progress live, to keep track of how I run into problems and what are my first intuitions when it comes to solving them.

So far, I've already built a functioning version of Pong:

Screenshot of my barebones version of Pong

A screenshot of my (completely basic) version of Pong in C++/SFML.

You can see that there are two paddles (controlled by the W/S and Up/Down Arrow keys respectively), a pong that bounces off of them and a scoring system (with some text that lets you see the score) that resets the pong every time it hits a "wall". So far so good.

On the coding side of things, I have 3 important classes so far: Pong (which handles the pong's characteristics, such as size, speed etc), Paddle (which does the same thing for the paddles) and Game, which, for the time being, implements all of the game logic (sidenote: I should probably move this logic up to the corresponding classes, although that might cause some problems with SFML's way of rendering/drawing stuff on the screen... I'll have to look into that).

My setup at the moment (in regards to this project) has as follows: I have a desktop Linux machine (on which I started developing the game yesterday) and a laptop running OSX. I'm now facing an unexpected problem; I've just cloned the game's repo on my laptop, everything compiles correctly, everything works as expected, but for some reason the game runs a lot slower. My first guess is that this has to do with the fact that speed is purely calculated based on FPS (or in any case based on the frequency of iteration of the main event polling loop). I think it's the next thing I should fix.

For the time being the speed calculations are dead simple. When it comes to the movement of the paddles, for example, I've just overriden the ++ and -- operators so that they make the paddle go up or down depending on a base speed, like:

paddle.setPosition(paddle.getPosition().x, paddle.getPosition().y + paddle.getSpeed())

(the code is actually in Paddle.cc so there's no need to reference it by name - we can just call the functions).

Anyway, I need to work on the way speed is calculated everywhere in the game.

So some time has passed, and what I've done is limit the FPS and push all my global "settings" into #defines. I don't know if it's the C++ way of doing things but at least it's cleaner than having a bunch of magic numbers everywhere. I've limited the FPS to 120 and played around with the numbers a bit so that it looks smooth; I need to also check how it plays on another computer to see if it maintains the same speed.

It did work! That was it. It makes sense I guess. Now I've done some reading on the subject, and apparently limiting the FPS is a very very bad idea, because it's acting on the main game loop and thus can cause input lag. But here the input isn't that high frequency and there's not too much of it anyway (the game is really simple), so I don't think that would be a problem.

Just added another small fix: I've replaced the #defines by static variable definitions, which is way cleaner and way more OOP in my opinion. So this:

turns to this:

Next up, I'd like to add a delay of some sort to launch the game. Right now it just starts as soon as it's launched and it doesn't give the players much time to prepare. The first idea I had was adding a small 3-second timer each time the pong resets so everyone can get ready, but that's actually a hassle to program (I have to add some logic to the main loop to "delay" it, but I can't just add a usleep or something in it cause it needs to always run or else the window doesn't render). Another idea is to just add something like "Press space to start" on the beginning of the game. I actually like not having a "delay" each time the pong resets, because in the end this game is all about agility; you should be ready for the next point once the previous one ends.

I've added the "space to start" thing, I think it looks way better now:

Screenshot of the game with the 'space to start' text added in the beginning

Now the game waits for you to press Space before starting.

I've just modified kind of a core mechanic: the pong's speed multipliers. In short, each time the pong hits a paddle it needs to accelerate so that the game becomes harder with time, and also so that it forces each point to end (otherwise the players could, in theory, continue indefinitely without scoring any points). The thing is, I used to accelerate the pong by multiplying the speed by a constant factor each time. The problem with that is that the pong appears to be accelerating exponentially and the game gets really hard really fast. What I've done is just speed un the pong incrementally, so that the speed increase appears to be more gradual.

The next step would now be creating a menu to welcome users, explain them how to play the game and also add a credits screen or something like that. That's easily done with a finite-state machine-like architecture, where what is shown depends on the state the application is on (for example: menu state, play state, win state, loose state).

Menu's done. I just have 3 menu items (play, controls and credits):

Screenshot of the main menu of the pong game I'm building

Main menu of the game.

It's not the cleanest code possible but hey, it works, and I will obviously clean that up later. For now, there are 3 menu states (main menu, controls and credits screens), and what is shown depends on what state the game is in. The pong that indicates the active/selected menu item moves each time the user taps the up/down arrow keys, according to the selectedMenuItem index. Each sub-menu/menu screen is drawn by a different function. I already see a way to group repeating code (like setting up text objects, loading the font onto them, drawing them etc) so I will optimize that later. I think the next thing I should do is give the user a way to stop the game and return to the main menu screen. Oh, I also hid the mouse cursor.

Okay so initially I wanted pressing the escape key in-game to trigger some kind of modal popup that would prompt you for verification before "quitting" the current game, but finally opted to not do that as I currently have no way of creating popups easily and it would really bloat the code. Oh, also I added a "quit" option in the main menu. What I need to do next is make the game end at 11 points (turns out that's the official Pong rules), and show an appropriate win screen, probably with replay / main menu "buttons" on it. Let's code that!

Screenshot of the win screen of the pong game I'm building

Win screen of the game.

I think that looks pretty good! I'll end the post around here, since I believe that at this point the game is fully functional. There's a lot of work that could still be done on it obviously: adding sounds, optimizing the code, perhaps even adding an install option to the Makefile...

It's been lots of fun building this game, I hope you've enjoyed coming along for the ride :)


Programming in x86 Assembly on OSX >