pongz

A friend and I made Pong in Javascript using HTML5 canvas. I then thought that it would be interesting to try it again and flex my C++ muscles.

The Github project: https://github.com/ryanbennettvoid/pongz

I didn’t plan on doing low-level pixel rendering, nor do I ever plan to in the near or distance future. So I chose the SFML library, which is a beautiful concoction of simple abstractions for managing windows, input, graphics, audio, networking and more.

Installing the lib was as easy as sudo apt-get install libsfml-dev since I use Mint Linux for development.

CMake. The first thing I wanted to do was get the CMake config in check. What I found interesting about including SFML into the project was that the program binaries had to be compiled first, then the SFML libs would be linked afterwords. I suck with compilers and stuff so I normally try to stick with header-only libraries. Nonetheless, I eventually cracked the code:

Architecture. Although my buddy and I managed to recreate Pong without classes, I would have great anxiety if I were to expand upon the code we wrote. So I made classes that made sense for the game.

Game is the high-level God object that glues everything together.

Ball is.. the ball. And Player represents the human player and computer player.

Tickable is a common interface for all rendered objects. A class that inherits Tickable must implement the tick method.

Passed through the tick method is the Game object, frame number, Event object for tracking inputs and Window object for rendering.

There is a strange thing happening here: a void pointer for the Game object. Why not just set the type as Game? Because the Game object itself is Tickable (a self-referencing class must be a pointer) and for whatever reason, it didn’t want me to use a Game* pointer either. Yep, my solution is dangerous and scary and stuff… but it works when I cast it back.

I then needed what other languages call “instanceof”. But it looks like C++ doesn’t have a straight answer to “how to you figure out the type of an object”. So I made all the objects inherit from an abstract class called Object that forced the implementation of a toString() method, that way each object could spit out a human-readable indicator of type. That came in handy when I needed to get all the players, for example.

I still needed to use dynamic_cast to at least be sure that an object was actually an… Object. Is this the best way to do the job? Probably not. Actually, I’m pretty certain it’s not. But it worked.

Logic. The physics of Pong are surprisingly simple. The velocity of the ball pretty much doesn’t change, only the direction does. And the direction only changes when the ball collides with something. How do we define a “collision”? There’s a moment when the ball is about to go off-screen. At that moment, I invert the X or Y direction and it works out.

There’s some slightly more complicated (and admittedly buggy) code for taking into consideration the player positions too.

Conclusion. I didn’t want to spend too much time on this project- just see what I could knock out in a few hours.

One thing I didn’t get around to doing was making the animations framerate-independent. When you just render everything as fast as possible, things can speed up and slow down depending on performance. What I’d do is have a global “delta” value which would be the duration between frames, and all displacements would be multiplied by that value. A bigger delta means bigger movements and vice-versa. In the end, the game speed would be independent from the framerate.

I really dig the SFML API. The renderable objects inherit from the sf::Transformable class, which has all the goodies you need to get/set the size, position, rotation of an object and perform boundary operations such as contains/intersects. I didn’t use the methods nearly as much as I could have, but next time I will just have my own classes inherit from the SFML classes directly.

From an architectural standpoint, I’ll try to avoid void* pointers and probably pointers in general, in favor of the ugly-but-safe unique_ptr and such. References are preferred.

Stylistically, I would normally place my starting curly braces on the same line as the parameters and space everything out more, but I went for a more mainstream style that I often see in other C++ code bases.

I’m a pretty big advocate of TDD nowadays, but I’m not too familiar with the TDD tools/ecosystem for C++. Something for later.

Leave a Reply

Be the First to Comment!

wpDiscuz