britrunner

aaron cooper

8 Oct 2023

Building a game in C++ (Part 2)

In Part 1, I kicked off my journey into the world of C++ game programming by getting to grips with basic game development practices. I learned how to use SFML to draw textured sprites into a window, respond to events like the user pressing the directional arrow keys, and moving the player’s sprite around the screen by updating sprite positions. Basic stuff, but I feel a lot more confident now after drawing moving pixels into a window.

Before coding anything more, I decided to pause and think about what I want to create at the end of this. I said in the last part that I’m doing all this to have fun learning C++, which is still true, but now that I’ve got some fundamentals down I’d like to actually try to aim at something to stretch where I want to go with this.

Check out the full game development series so far here: Game Dev.

Key game features

I considered the direction I wanted to move in and I chose to focus on building a Sci-fi Roguelike/RPG game that’s heavily inspired by the 1999 PC game System Shock 2.

System Shock 2 image of Shodan the rogue AI

SS2 blended elements of first-person shooter, survival horror and role-playing game genres, all wrapped up in a dark sci-fi setting. I get incredibly nostalgic thinking about the experiences I had growing up playing it, so I’m absolutely looking at it through ruby-tinted glasses! The important thing though is it’s a theme I really dig and I can envisage portraying in a 2D game.

I’d like to put my own spin on things, so I won’t be remaking this decades-old game (please, Nightdive, do it soon!), but instead I’ll try to capture some of the aspects that I remember fondly.

Below are a few ideas I’ve had so far.

Multiple skills, finite resources

System Shock 2 example skills tree

SS2 was very re-playable because you built your own character by levelling up different skills to become more effective in a specific area, but it deliberately gave you only enough points in a single playthrough to maximise one or two areas. This meant you’d probably be curious what the game would be like if you’d decided to spec your character differently, so you’d want to play it again. I prefer this over letting the player eventually get every skill available, because it means every skill point is valuable and it makes you think carefully about your character progression.

System Shock 2 example inventory

Speaking of finite resources, inventory management was also a big deal, so much so that every item would use up some of your inventory space. You had to play Tetris to fit everything in once you had a few large items. I’m not a big fan of such manual inventory , but in general I like the idea of limiting the player’s carrying capacity to encourage thinking carefully about what items to keep or drop.

Brutal mechanics

SS2 wasn’t easy. It forced new players to creep around, perk up their ears to the slightest of noises and constantly watch their back. This was partly because of the horror elements, but mainly because it was such a punishing game to play. You had very limited health and resources throughout, and enemies had harsh attacks.

This is what I want in my game too: to keep players on their toes with mechanics that’ll constantly challenge them and punish slip-ups in a way that makes them think: “that could have been avoided with better play”.

Dark, claustrophobic settings

It’s impossible to think of the System Shock games without thinking about dark corridors, artificially-lit rooms and uncountable colourful buttons and bright monitors. I like these aesthetics and I’d like to see how far I can take them in a simple 2D game. There’s lots of other media out there with a similar vibe in movies, books and other games, so I’ll likely look for more inspiration and find a sweet spot that makes my game look and feel interesting to explore.

Screenshot of System Shock 2 from the Med-Sci level

An engaging, twisty story

Whilst I don’t imagine I’ll be spinning a masterwork of script-writing, I would love to have a crack at piecing together an interesting plot that’ll keep players engaged and wondering what’s coming next. SS2 nailed it in my mind (my ruby-tinted lenses again?), with a “helpful” 3rd party that guides the player through the game with objectives and rewards (skill points), and a great plot twist in the middle that flips everything on its head. It’s also a great story in my mind because it has you questioning who’s really good or bad, and who deserves to live or die. You may not actually have the power to affect the outcomes, but

Roguelike aspects

The main aspect of Roguelikes that I’d like to incorporate would be procedural generation. I stumbled on some interesting stuff recently, such as wave function collapse, which is an algorithm for generating levels from an assortment of possible tiles. Otherwise if I feel like hand-crafted levels would be better for storytelling, I might try randomly generated enemies or items.

I may also think about interesting player death mechanics such as permadeath or revivals from a previously activated object like a healing station, such as in SS2.

Top-down 2D perspective

There’s a bunch of different ways of visualising a game in 2D, but I’d like to go for a top-down perspective with the side profile of characters and items visible from a single angle. Think of retro games like the original Pokemon series on Gameboy, or more recently a game like Undertale.

Screenshot of Undertale as an example of a 2D top-down perspective

I’m undecided on the art style, although I’m leaning towards a pixel art look.

A game development project methodology

Before diving back into Visual Studio, I was recommended a video by YouTube’s lovely algorithm that I’d like to share. It’s given me a way of thinking about how I approach this and other side-projects I may do in the future.

https://www.youtube.com/watch?v=NsMHicoZTzQ

This is a great video to watch regardless of whether you’re building a game, a website, or anything else on your own.

The TL;DR for me is that I can think of dividing my time up into 2 different kinds of work: Prototyping and Production.

There’s a line that can be drawn between these two phases, and this helps focus the mind on doing one thing at a time, working towards the end goal of having a finished product. When the line is blurred, it’s easy to fall into cycles of doing unenjoyable busywork.

Back into the code

All of the above have been big deviations from coding, but I think everything I’ve penned will help me moving forward on this project. Yes, I’m still mainly doing all this to learn C++, but I want to also enjoy building something I like!

Level tiling system

Previously, I coded up a really basic single-image texture background, but in my final game I’d like a system that builds levels out of tiles that are sourced from sprite sheets. The problem is, how will my game know which frames it should take from a sprite sheet to render levels?

A simple solution would be to use something like a tilemap. This is way of mapping out a 2D level tile by tile. Each tile can be set to a single value, which could be anything simple. For example, I might create a tilemap looking like this:

Terminal window
0 0 0 0 0 0
0 1 1 1 1 0
0 1 2 2 1 0
0 1 2 2 1 0
0 1 1 1 1 0
0 0 0 0 0 0

What does each number mean? As the developer, that’s up to me! I might decide that 0 equals a blank white tile, 1 equals a grey tile and 2 equals a green tile. My program can then parse through this tilemap and based on the number render the appropriate type of tile.

I was thinking of coding up a function that does this parsing, but luckily I did a little more research and found a program and a library that together solve a bunch of issues tilemaps throw up.

Tiled level editor

Tiled is a 2D level editor that’s completely separate from any game framework or renderer and saves its tilemaps in XML and CSV formats, making the data easy to parse and interpret in any way that a game needs to. Tiled actually solves a variety of problems I’d anticipated with regards to tilemaps, such as how I will edit levels and see the changes, and how I will manage different tile layers, which will be crucial for placing objects on top of the base level tiles.

Installing the tmxlite C++ library

Before manually parsing the Tiled tilemaps, I looked into C++ libraries and found tmxlite, which I liked because it handled the parsing and converting from the raw data into C++ objects that are easy to work with. It’s again completely decoupled from SFML or any other game libraries, so I’ll just need to turn the objects into drawable tiles.

I want to mention installation of this library because this was my first real test at bringing in external libraries without having a detailed guide. I started by cloning the entire repo outside my project (in the same directory where I had SFML files stored).

The guide talks about using CMake to build the required files needed for linking, but I chose to use Visual Studio. I opened up the tmxlite/tmxlite.vcxproj file, and then simply went to Build > Build tmxlite. After this, it produced files inside the build directory, which is mentioned in the console output. Importantly, it produced a .lib file inside x64/bin/DebugStatic.

Back in my own Visual Studio project, I opened the project Properties and added the following:

With these in place, I was then able to try out the basic tmxlite example shown here.

Creating a sprite sheet

Something I knew I’d need to face eventually was creating my own graphics. I had a look around and found the program Aseprite to be a solid yet simple pixel art editor with handy features for game spritesheet creation and animation. It cost less than $20 SGD, so I took the plunge.

I did up a really basic spritesheet to work with initially, based on the virtual reality training levels in System Shock 2: dark backgrounds with stark neon lines. Nothing too fancy for now.

My first attempt at a basic sci-fi spritesheet for level tiles

I saved this single graphic as a PNG and imported it into Tiled. Each tile I’d created within a 32x32 pixel square, so I set Tiled to parse it at that specific size per tile, and it worked well. I was able to start drawing tiles onto an orthogonal grid:

A basic level created in Tiled

Bringing it all together

Once I’d saved my Tiled level, I was then able to import it into my game via the tmxlite library mentioned above. By using the tmxlite example code in their repo, I was able to quickly see how to iterate over each tile in the map. It was then just a matter of turning each tile into a Sprite object and saving them in a vector (a dynamically sized array).

Finally, I iterated over the sprites vector, passed each sprite to the window.draw() method on my original SFML window, et viola:

My game window rendering the Tiled level tiles as expected

I was so chuffed to have my 2D Tiled map displaying in my window!

It was rendering the tiles as-is from the spritesheet, which meant each tile was 32x32 pixels in the window. I’ll need to investigate how best to scale the tiles. What I’d love is for SFML to handle scaling and positioning of the tiles inside a frame that I can move around (as opposed to being relative to the window), which would save me some extra calculations needed to get everything correctly aligned.

Basic level creation workflow

As a visual recap, here’s the workflow I’ve got working to go from raw pixels into the game:

Export spritesheet to PNG
Save map as TMX
Set sprite texture
Set sprite position
Draw tiles in Aseprite
Import spritesheet into Tiled
Draw map in Tiled
Read TMX file into C++ game
Import spritesheet PNG linked in the TMX
Parse tiles data
Store vector of tile sprites
Draw tile sprites based on their positions

Summary

I’m glad I put away my IDE for while to just think about what I wanted to make. It wasn’t enough to just say “a 2D game”. I see this as a golden opportunity to build something I’ve never built before and it’s something I’ve wanted to do for decades. My inspirational material from the late 90s game System Shock 2 has given me a much stronger desire to create this work that I can genuinely see myself enjoying the end result of.

Besides this, I’m still amazed I was able to string together a workflow that I can use to create graphics, build levels using them and render them into my game. This is a major bit of coding work that I would have had to do by hand if I hadn’t discovered Tiled.

In the last part I said I wanted to get a rough plan together, which I’ve been able to do. Next, I’ll continue to work in the “prototyping” phase and start building out systems to start making this an actual playable game. I’m also itching to do up some proper graphics for it, but I’m holding back on the artwork until I’ve got more of the core game together (and a graphics tablet that I’ve ordered from the US). A few things I want to get done in no particular order are:

I don’t think I’ll get to most of these too soon, but these are all definitely on the roadmap.

Hope you enjoyed Part 2, keep an eye out of Part 3 in the coming week or so!

Credits

All the images from other games seen in this article were copied from various websites found via Google images. I, of course, don’t own the rights to those games and didn’t snap those screenshots personally.