Web Dev Diaries

A blog and resource for modern web development

Building a game in C++ (Part 1)

A screenshot from the game I’m building in C++, showing a player character on an AI-generated background texture.
A screenshot from the game I’m building in C++, showing a player character on an AI-generated background texture.

Today, I’ll be sharing about my first foray into the 40-year-old programming language: C++! Join me as I fumble my way through setting up my environment and writing my first lines of code as I work towards the goal of creating a 2D game.

I decided not to paste all my code here, partly because I’m changing it so often as I learn more and iterate on the design. Consider this article less of a tutorial, more a journal of my time using C++ and learning about game development architecture. I’m happy to answer any technical questions in the comments if I can, so don’t be shy.

Check out the full game development series so far here: Building a game in C++.

My experience in game development (or lack thereof)

I’m a web developer by trade, so JavaScript has been my bread and butter for a good 13+ years. I’ve always had a fascination with programming and games, so much so that my university degree was in game development, although I chose not to pursue it as a serious career option.

Although my degree was in game development, I only picked up very high-level concepts, and used C#, Java, Flash and Adobe Director (yuck…) to build the most basic programs that one might loosely call “games”. Now that I’m close to my mid-30s and still have a love for playing video games, I decided it was time to start learning - properly - how to build games.

Why C++?

Virtually any programming language can be used to build a game. I could create one using web technologies and probably get something functional in a browser fairly quickly. This isn’t in the spirit of what I’m really trying to achieve here though. I’m not interested in speed of delivery, just learning and fun!

I wrote an article not too long ago where I shared about my mindset when it comes to just doing something, instead of getting snagged on over-planning what you’re going to do. Here’s the article if you fancy challenging yourself: Building things that no one wants.

The reasons I’m keen on C++ over other languages are a few:

  • It’s second only to C as one of the most influential languages, inspiring the creation of many of today’s most used languages, which to me is really cool and I’d love to see how it works first hand.
  • It’s heavily used in game development because it’s fast and easy to work with (compared to C), so it’s a natural consideration in that regard.
  • It’s such a fundamental systems language that I’m deeply interested in learning its quirks and gaining more appreciation for the features I rely on every day in higher-level languages like JavaScript.

I’ll be using the latest version currently available, which is C++ 20, although 23 is due for release soon.

Let’s start!

I downloaded Visual Studio Community Edition as it’s the easiest IDE to grab for the C languages. VS Code could also be used, but requires plugins and the manual installation of a C compiler at the very least.

Once VS was installed, I created a new app from the Command Line Application template to get me started. Running the app from the IDE compiled the raw C++ code into an executable binary. My terminal popped up with the expected output:

My first “Hello World!” in C++

I immediately liked the developer experience here - easy installation of the IDE with all the tools and compiler set up, and a one-click run from a basic template that just works.

I’m not going to focus too much time learning C++ basics through tutorials, I’d rather just get stuck in and learn as I go.

Choosing a library

If this were a serious, outcome-focused project, by now I should have identified the intended audience, scraped together some core requirements, and maybe have some diagrams drawn up to describe potential game loops.

Of course, I hadn’t done any of these things. I just wanted to get into some C++ quickly! Happily, there’s game development libraries that abstract away the low-level stuff you’d normally need to hand-code yourself, such as pushing graphics onto the screen. Some popular libraries in the C++ ecosystem are SFML, SDL and Raylib.

It’s easy to waste time choosing the perfect tool, so I simply went with one that looked recently updated and had enough learning resources available online for beginners - SFML.

SFML (Simple and Fast Multimedia Library)

I discovered SFML from this game development guide: Building a simple game engine in C++, which also has a good starting project to reference.

My first C++ reality check: dependency management

In NodeJS, you’ve got NPM to handle fetching 3rd-party libraries from a central repository, installing them into your project and tracking the versions required for future setups of the project on other machines. Python and Java have similar tools available that most developers use.

In C++, you’re required to manually source and download libraries, and then manually link them into the projects you’re working with. Oh, and if you’re using dynamic libraries, those DLLs need to be manually copied into the directory where your app’s executable sits (after it’s compiled). This article by Amir Kirsh talks about other issues with C/C++ dependency management compared to other ecosystems. Amir also mentions some dependency management tools to help, but I chose not to explore these (for now).

Setting up SFML

Despite the above realisation, installation of SFML - thankfully! - was not too painful in Visual Studio, which was entirely thanks to SFML’s excellent documentation. The setup steps I followed are here: sfml-dev.org/tutorials/2.6/start-vc. I downloaded the files for v2.6.0, placing the SFML folder outside my project for other projects to use in future if needed. Linking them into the project via Visual Studio was easy following the documentation carefully.

Writing some code

Loosely following the SFML guide mentioned above, plus this excellent SFML tutorial on YouTube, I created some basic classes to lay the groundwork of the game I was building.

Creating the game engine

I created an Engine class to orchestrate the game’s setup and runtime loop. Its responsibilities are to:

  • Define the window that SFML will draw things into
  • Define elements that will be rendered
  • Handle running the game loop
  • Handle user inputs
  • Redraw things as required

This is probably too many things for a single class to handle (SRP…), but I went with this setup for simplicity and will divide it up later if it gets too messy. Interestingly, C++ allows you to define a single class’s methods across separate .cpp files (although I reckon it’s a code smell if your class is too big to fit inside a single file). There’s also a header file ending with .h that will define the interface (methods & members, public & private) that the class should follow, so it’s common to have something like Engine.h and Engine.cpp next to one another: the interface contract (.h) and the implementation (.cpp).

My initial Engine class interface looked like this:

// Engine.h

#pragma once
#include <SFML/Graphics.hpp>
#include "Player.h"

class Engine
{
private:
	sf::RenderWindow window;
	sf::Sprite bgSprite;
	sf::Texture bgTexture;
	Player player;
	void draw();
	void pollEvents();

public:
	Engine();
	void start();
};

The sf:: prefixes before the types indicate they come from the sf namespace inside the SFML library.

I initialised the engine inside my program’s default main function and triggered the start of the game loop with a call to Engine.start().

Rendering sprites

I hit an issue early on when I wanted to load a texture for the game background - image files wouldn’t load when calling the SFML Texture .loadFromFile() method. The error message just said it was unable to load the file, without printing the file name I passed. The problem: I was running the app in the Debug build configuration in Visual Studio, but I’d linked the non-debug SFML libs in the project configuration. The fix: I updated the SFML lib links under Linker > Input so that they all included the -d suffix. The SFML docs cover this. This one had me stuck for a while!

Once I’d got textures loading in, I initialised the sprite for the background image, which is the element that actually gets drawn by SFML. The cool thing about having textures and sprites as separate entities is that a single texture can be shared by multiple sprites. I can imagine this being useful for taking different slices of a single spritesheet image.

The rendering logic I placed inside void Engine::draw() method, which gets called at the end of my game loop. This will handle drawing the background and player sprites, and anything else in future.

Handling key presses

Once I had the background image getting displayed, I was eager to start handling user inputs. Before the draw() method gets called, the game should check for any events that occurred so that object properties can be updated as needed before sprites are redrawn into the window.

I defined a method void Engine::pollEvents() that I could call just before draw() in the game loop. I then referenced SFML’s window.pollEvent() method inside another while loop inside pollEvents. It’s from here that any events can be picked up and acted on. Following the video guide I mentioned, I added logic to handle “exit” events to close the game window, such as the user pressing the Escape key.

I’ll need to extend the pollEvents method later with key press handlers for the player movement.

I’d like to address something in this code that confused me initially:

while (window.isOpen())
{
	while (window.pollEvent(ev))
	{
		switch (ev.type)
		{ /* handle the event.. */ }
	}
}

I asked myself: why do I need a nested loop? Surely this is really inefficient? Surely I’d just write an event handler for the events I want to listen for? If there’s one thing Hackerrank and Leetcode have taught me it’s to NEVER nest loops! Think of the Big-O time complexity!

The reason for this is SFML collects together all events that occurred in the last tick (which might be multiple events), before making them available via the output of pollEvent() to iterate over. That inner loop is there to handle each event that happened, which might have been a few different keys being pressed at once. That loop’s logic only runs as new events are picked up, so it’s perfectly OK.

Creating a controllable character

I created a Player class to hold everything related to the user’s controllable character in the game, like the visuals (texture, sprite) and internal state (position, direction).

I then added basic movement handling via a move() method. At first, I allowed passing in the new x and y values each time, but that meant calculating how much to move by wherever this function gets called. I changed it so the method accepted a direction name and the player class can decide how to update its own position. It looked something like this:

// Player.cpp
enum PlayerDirection { up, down, left, right };

void Player::move(PlayerDirection direction)
{
	int x = 0;
	int y = 0;

	if (direction == PlayerDirection::left)
	{
		x = -(this->maxSpeed);
		this->setDirection(PlayerDirection::left);
	}
	/* other conditionals.. */

	this->setPosition(this->position.x + x, this->position.y + y);
}

void Player::setPosition(int x, int y)
{
	this->position = sf::Vector2i(x, y);
	this->sprite.setPosition(x, y);
}

This won’t allow movement in all 360 degrees as it’s tied to one of just a few directions, but this was acceptable for the game I wanted to create. You’ll see it calls setPosition() at the end, which updates the player’s position value and the sprite position at once.

All I needed to do then was add window.draw(player.getSprite() into the Engine’s draw() method, so whatever the position value of the sprite is gets drawn into the window.

I also snuck in a call to setDirection(), which is my way of changing which direction the player character is facing. I used a basic free spritesheet texture that only faces the player in a single direction, so to change the direction I did a little trickery with the sprite to mirror it on the x axis:

if (direction == left)
{
	this->sprite.setTextureRect(
		sf::IntRect(
			this->frameSize.x,  // x
			0,                  // y
			-this->frameSize.x, // width
			this->frameSize.y   // height
		)
	);
}

The IntRect object tells the sprite which area of the texture image should be shown. Think of it like a window that only looks at a small piece of a bigger picture. If you pass a negative value in the width or height (3rd and 4th arguments respectively), the sprite will mirror the rectangle of the image it’s focused on.

Here’s the single-direction spritesheet I used, courtesy of Craftpix.net:

Player idle animation spritesheet

For simplicity, I only sliced the first frame in the sheet and mirrored that when it needed to face left. In future, I’d also like to implement the animation logic to cycle through all available frames, which will make the player look like it’s gently moving when starting still.

Architecture review

At this point, I wanted to pause and review what I’d built so far. It’s probably also been tricky to follow what exactly I’ve done from the above text alone, so here’s a state diagram that illustrates the flow of events:

stateDiagram-v2
	createWindow : Create SFML window
	createAssets : Create engine and player objects
	loadTextures : Load texture files, define sprites
	runLoop : Run main game loop in Engine
	pollEvents : Was a key pressed?
	handleEvents : Update player position based on key press
	state didPress <>

	[*] --> createWindow
	createWindow --> createAssets
  createAssets --> loadTextures
	loadTextures --> runLoop
	runLoop --> gameLoop

	state "Game loop" as gameLoop {
		draw --> pollEvents
		pollEvents --> didPress
		didPress --> handleEvents : Yes
		didPress --> draw : No
		handleEvents --> draw
	}

	gameLoop --> [*]

Summary

I’ve loved taking my baby steps with C++ and SFML. It’s a very different way of working with code compared to building web interfaces. Games work by running in loops, rendering graphics into a frame, updating object values in reaction to player inputs or timers, then rendering the next frame based on the new values. On the other hand, web UIs are mostly about displaying static content and writing logic in event handlers that only get called when the user does something.

Here’s a little look at what I have so far, a controllable character in 4 directions against a fixed image background texture:

A player character moving in different directions

This is pretty basic and far from perfect, but this is a good starting point for me. In building this and writing up the exploration here, my mind has been opening up to what I’d actually like to aim for.

By the next article, I’d like to have a rough plan drawn up and to start actually architecting a game engine that I can keep expanding. I’m really excited to continue the journey!

comments powered by Disqus