Home Game Development Procedural Content Generation for C++ Game Development

Procedural Content Generation for C++ Game Development

By Dale Green
books-svg-icon Book
eBook $43.99 $29.99
Print $54.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $43.99 $29.99
Print $54.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    An Introduction to Procedural Generation
About this book
Procedural generation is a growing trend in game development. It allows developers to create games that are bigger and more dynamic, giving the games a higher level of replayability. Procedural generation isn’t just one technique, it’s a collection of techniques and approaches that are used together to create dynamic systems and objects. C++ is the industry-standard programming language to write computer games. It’s at the heart of most engines, and is incredibly powerful. SFML is an easy-to-use, cross-platform, and open-source multimedia library. Access to computer hardware is broken into succinct modules, making it a great choice if you want to develop cross-platform games with ease. Using C++ and SFML technologies, this book will guide you through the techniques and approaches used to generate content procedurally within game development. Throughout the course of this book, we’ll look at examples of these technologies, starting with setting up a roguelike project using the C++ template. We’ll then move on to using RNG with C++ data types and randomly scattering objects within a game map. We will create simple console examples to implement in a real game by creating unique and randomised game items, dynamic sprites, and effects, and procedurally generating game events. Then we will walk you through generating random game maps. At the end, we will have a retrospective look at the project. By the end of the book, not only will you have a solid understanding of procedural generation, but you’ll also have a working roguelike game that you will have extended using the examples provided.
Publication date:
January 2016
Publisher
Packt
Pages
304
ISBN
9781785886713

 

Chapter 1. An Introduction to Procedural Generation

When you load an image on a PC, a song on an iPod, or a book on a Kindle, you load it from storage. That image, song, and book already exists as a whole, and whenever you want to access it, you grab the whole previously created thing. In the case of music or a video, you can stream it in chunks, but it still already exists as a whole in storage. Let's compare this to buying a ready-made desk from a furniture store. You get the entire desk as one single thing and that's that; you have a desk.

Now, let's imagine that instead of buying a complete desk, you buy one that's flat-packed. Instead of getting a pre-built desk, you get all the pieces that you need to build one, and instructions on how to do so. When you get home, you can follow those instructions, and you will have a desk. If you feel so inclined, you can even deviate from the instructions and create a unique desk that is different from that of everyone else.

Let's use this analogy in the context of game development by substituting the purchasing of a desk with the loading of a level. In the first case, we loaded the level as a whole, as it was pre-built. However, in the second example, we got all the pieces that we need to build a level and put them together ourselves in whatever order we choose.

This process of something being created via an algorithm or procedure, as opposed to already existing, is called procedural generation. The desk was created procedurally as you followed an algorithm to put its pieces together. The same goes for the game level. This can be extended to almost anything. For example, music, images, games, and text can all be procedurally generated.

In this chapter, we will cover the following topics:

  • Procedural generation versus random generation

  • Generating pseudorandom numbers in C++

  • Seeds

  • The benefits and drawbacks of procedural generation

  • A brief history of rogue-like games

  • How to implement procedural generation

 

Procedural generation versus random generation


I'd like to make a distinction before we go any further. In this book, we're going to talk a lot about procedural generation and random generation. These terms are often used interchangeably, but they are not the same thing. Therefore, let's take a moment to define them.

Procedural generation

Procedural generation is the process of creating content using an algorithm. This in itself has no element of randomness. If the functions, expressions, algorithms, and inputs that are used to generate the content remain the same, then you'll always get the same results. This is due to the fact that computers are deterministic, which is something that we'll cover shortly. Procedural generation is not inherently random.

Random generation

Randomness is induced when we give these algorithms different inputs or alter their expressions. This variance is what creates the variety of the output. When someone says something was procedurally generated, they usually mean procedurally generated utilizing randomness.

 

Introducing randomness


Computers are deterministic machines. This means that if you give them the same input, and perform the same operations, you'll get the same output every time. With respect to the desk example, everyone gets the same pieces, follows the same instructions, and so builds the same desk.

Again, using the context of games, if everyone gets the same assets and algorithms to put them together, we will all get the same game and experience. Sometimes, this is the goal. However, in our case, we want to create game systems that are unpredictable and dynamic. Therefore, we need to introduce an element of randomness to procedural generation.

Pseudorandom number generation

Random number generation is simply the process of picking a number at random. This is pretty straightforward for us, but it is a much tougher task for a computer. In fact, it's impossible for a computer to generate a truly random number without special hardware. You'll understand why this is so in a moment.

The next best thing is pseudorandom number generation. The word pseudo literally means not genuine. Therefore, pseudorandom number generation can be thought of as a fake random number generation. The numbers appear to be random but are actually the result of complex equations and algorithms that could in fact be calculated in advance.

Bear in mind that not all pseudorandom number generators are built equally. For applications such as trivial simulations and games, fairly linear algorithms can be used and are perfectly suitable. However, pseudorandom number generation is also used in applications such as cryptography, and will use much more complex algorithms so that the outcome cannot be determined via patterns created from earlier outputs.

The pseudorandom number generators that we use as developers fall firmly into the first category and are perfectly suitable. Luckily for us, C++ offers a number of ways in which trivial pseudorandom numbers can be generated. Throughout the course of this book, we will use std::rand() and std::srand(), both of which standard C++ functions that are included in <cstdlib> library.

Tip

Learning how to read and extract information from documentation is a skill that I feel is often overlooked. With a multitude of great forums at hand it's easy to go straight to Google for a solution to your problem, but first, always read the documentation. http://www.cplusplus.com is a great C++ reference, and SFML is fully documented at http://www.sfml-dev.org/documentation/.

Why computers can't generate truly random numbers

We now know that computers can't generate random numbers, and that we generate pseudorandom numbers instead. Let's have a look at why this is so.

The reason behind this is the same as the reason why two computers will reach the same output given the same input and operation; computers are deterministic. Everything that a computer produces is the result of an algorithm or equation. They are nothing more than highly sophisticated calculators. Therefore, you can't ask them to act unpredictably.

True random numbers can be generated, but you need to utilize systems outside the machine. For example, at https://www.random.org/ you can generate truly random numbers using atmospheric noise. There are other systems that are akin to this, but unless you are generating random numbers for something important such as security purposes, trivial pseudorandom number generation will suffice.

Generating random numbers in C++

Let's start coding by writing a small program to generate some pseudorandom numbers. To do this, we will use the std::rand() function. It generates a pseudorandom integer in the range between 0 to RAND_MAX. The RAND_MAX variable is a constant defined in <cstdlib>. Its value will vary depending on the library that you are using. On a standard library implementation, it's guaranteed to be at least 32767.

Tip

If you're already familiar with this topic, feel free to skip ahead to the sub-chapter named Seeds.

You can download the code for this program from the Packt website at http://www.packtpub.com/support. It will be present in the Examples folder, and the project name is random_numbers:

// Random number generation
// This program will generate a random number each time we press enter.

#include <iostream>

using namespace std;

int main()
{
  while (true)
  {
    cout << "Press enter to generate a random number:";
    cin.get();

    // Generate a random integer.
    int randomInteger = rand();

    cout << randomInteger << endl << endl;
  }

  return 0;
}

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

This is a very simple console application that makes a call to std::rand() every time we press the Enter key. This returns us the pseudorandom number, and we pass it to std::cout to display it. That's how easy it is!

Generating random numbers within a range

The previous code generated numbers between 0 and RAND_MAX. That's great, but we'll usually want more control over this in order to generate numbers within a certain range. To do this, we are going to use the modulo operator.

Tip

In C++, the modulo operator is the % symbol. This varies between languages, but is generally either % or Mod.

The modulo operator returns the remainder of the division between two numbers. So, 9 mod 2 is 1, as 2 goes into 9 four times with 1 left over. We can use this to create a range for the pseudorandom number generation. Let's generate a number between 0 and 249.

To do this, we need to make the following change:

// Generate a random integer.
//int randomInteger = rand();
int randomInteger = rand() % 250;

Run the program a few times now, and you'll see that all the results are limited to the range that we just defined. So now we can generate a number between 0 and n, but what if we don't want our range to start from 0? To do this, we need to make one more change to the line that generates a number:

// Generate a random integer.
//int randomInteger = rand() % 250;
int randomInteger = rand() % 201 + 50;

Remember that the number we used in the mod calculation will generate a number between 0 and n-1, and the number we add afterwards will increase the range by that amount. So here, we generate a number between 0 and 200 and then increase the range by 50 to get a number between 50 and 250.

Tip

If you're not fully comfortable with the math behind what we're doing here, head over to Khan Academy. It's a fantastic resource for learning and has lots of great mathematics-related material.

Run the program and note the first five numbers that are generated. In my case, they are 91, 226, 153, 219, and 124. Now, run it again. You'll notice that something strange happens; we received the exact same numbers.

They were generated in a pseudorandom manner, right? Maybe it was just a fluke. Let's run it again and see what we get. You will get the same result again. To understand what's happening here, we need to take a look at seeds.

 

Seeds


We just created a program to generate pseudorandom numbers, but every time we run it we get the same results. We know that these numbers are the results of complex equations and algorithms, so why are they the same? It's because each time we run the program, we're starting with the same seed.

Defining seeds

A seed provides a starting point for an algorithm. So, in the previous example, yes we're using complex algorithms to generate numbers, but we're kicking off the algorithm at the same point each time. No matter how complex the algorithm is, if you start at the same point, and perform the same operations, you're going to get the same results.

Imagine that we have three people, and each person is about to walk the same path by 5 steps. If they all start from the same square, they will end at the same square:

Now, in the next diagram, we give these three people unique starting positions. Even though they are doing the same actions as before, and are on the same path, their results are different because they started from different locations:

In this analogy, the path is the algorithm, and the starting square is the seed. By changing the seed we can get different results from the same actions.

You will have most likely used seeds before and not even known it. Games that procedurally generate worlds, such as Minecraft and Lego Worlds, give you the option to set a seed manually before generating a world. If your friend generates a world that looks great, they can grab their seed and give it to you. When you input that seed yourself, you kick off the algorithm at the same place that your friends did and you end up with the same worlds.

Using seeds

Now that we know what seeds are, let's fix the previous example so that we don't keep generating the same numbers. To do this, we will use the std::srand() function. It's similar to std::rand(), but it takes an argument. This argument is used to set the seed for an algorithm. We'll add the call to std::srand() before we enter the while loop.

Tip

You only need to set the seed once per run of the application. Once std::srand() has been called, all the subsequent calls to std::rand() will be based upon the updated initial seed.

The updated code should look like this:

// Random number generation
// This program will generate a random number each time we press enter.

#include <iostream>

using namespace std;

int main()
{
  // Here we will call srand() to set the seed for future rand() calls.
  srand(100);

  while (true)
  {
    cout << "Press enter to generate a random number:";
    cin.get();

    // Generate a random integer.
    int randomInteger = rand() % 201 + 50;

    cout << randomInteger << endl << endl;
  }

  return 0;
}

Now when we run this code we get different results! I got 214, 60, 239, 71, and 233. Don't worry if your numbers don't match mine exactly; they are both CPU- and vendor-specific. So, what will happen if we run the program again? We changed the seed. So we should get different numbers again, right?

Not quite. We called std::srand() and set a new seed, but each time we run the program we're setting the same seed again. We're kicking the algorithm off at the same position each time, so we're seeing the same results. What we really want to do is randomly generate a seed during runtime so that the algorithm always starts at a new position.

Generating random seeds during the runtime

There are many ways to achieve this, and your use case will determine which method is suitable. For us, as game developers, something relatively trivial such as the current system time will usually suffice.

This does mean that if you run the program at the exact same time you'll get the same results, but that's almost never going to be a problem for our use. C++ provides us with a nice function to get the current time, time(), which is located in <ctime>.

Let's update the program one last time and pass time() as a parameter in std::srand() so that we generate unique numbers with every run:

// Here we will call srand() to set the seed for future rand() calls.
//srand(100);
srand(time(nullptr));

Now, every time we run the program, we get unique numbers! You may have noticed that if you run the program multiple times in succession, the first number is always very similar to the last run. That's because between the runs time doesn't change a lot. This means that the starting points are close to each other and the results reflect this.

Controlled randomness is the key to generating random numbers

The process of generating random numbers is a huge component in creating systems that procedurally generate game content. There are lots of ways in which random data is generated, such as noise maps and other external systems, but in this book, we'll stick to these simple C++ functions.

We want systems that are predictable enough to give us control over them as developers, but they should be dynamic enough to create variations for the player. This balance can be hard to achieve, and sometimes games get it wrong. Later in this chapter, we'll look at some of the things that you have to watch out for when incorporating procedural generation into a game project to avoid this.

 

The use of procedural generation in games


Now we know what procedural generation is, and that it's the element of randomness we add that lets us create dynamic systems, let's take a look at some examples of how it is used in games. There are countless ways in which it can be utilized; the following are just a few major implementations.

Saving space

Necessity, as the saying goes, is the mother of invention. As developers of today we're spoiled with the hardware that we have at our disposal. Even the most baseline machines that you'll get today will have a hard drive of 500 GB in size and up as standard. This is quite a luxury considering that just a couple of decades ago that would be MB and not GB.

Game distribution was also a very different game back then. Today, we either buy games on a physical disk, with Blu-ray disks offering a whopping 25 GB per layer, or download them off the Internet, where there are no size restrictions at all. Keeping this in mind, now consider the fact that the size of most Nintendo Entertainment System (NES) games was a mere 128 to 384 KB! These storage restrictions meant that game developers had to fit lots of content into a small space, and procedural generation was a great way to do this.

Since building large levels and storing them wasn't possible in the past, games were designed to build their levels and resources algorithmically. You'd put all the resources needed on your storage media, and have the software assemble the level at the player's end.

Hopefully now, the earlier desk analogy makes more sense. It's just like how flat-packed furniture is easier to transport, and it can then be built at home. As hardware has developed, this has become less of a problem, but it was a great solution for early developers who had storage concerns.

Map generation

One of the most prominent uses of procedural generation in modern video games is the generation of game maps and terrain. The extent to which this can be used is vast, and ranges from generating simple 2D maps to full 3D worlds and terrain.

When procedurally generating 3D terrain, noise maps, such as the ones generated by Perlin noise, are used to represent random distribution by producing an image with areas of both high and low concentration. This data, the variance in concentration and intensity, can then be used in many ways. When generating a terrain, it's commonly used to determine the height at any given position.

The procedural generation of complex 3D terrain is beyond the scope of this book. However, we will generate 2D dungeons later in this book.

Tip

If you do want to explore 3D terrain generation, read up on terms such as "fractal terrain generation", "height maps", and "noise generation". These will put you on the correct path.

 

Texture creation


Another prominent example of procedural generation is the creation of textures. Similar to terrain generation, the procedural generation of textures uses noise to create variance. This can then be used to create varying textures. Different patterns and equations are also used to create a more controlled noise that forms recognizable patterns.

Generating textures procedurally like this means that you can potentially have an unlimited number of possible textures without any overhead on storage. From a limited pool of initial resources, endless combinations can be generated, an example of which can be seen in the following image:

Perlin noise is just one example of the many algorithms that are commonly used in procedural generation. The study of these algorithms is beyond the scope of this book, but if you want to further explore the use of procedural generation, it would be a good place to start.

Animation

Traditionally, game animations are created by animators, and then exported as an animation file that is ready for use in the game. This file will store the various movements that each part of a model will go through during animation. It then gets applied to the game character during runtime. The player's current state will determine which animation should be playing. For example, when you press A to jump, the player will change to a jumping state, and the jumping animation will be triggered. This system works great, but it is very rigid. Each step, jump, and roll is identical.

However, procedural generation can be used to create real-time, dynamic animation. By taking the current position of the character's skeleton and calculating the multiple forces that are being imparted upon it, a new position can be calculated. The most prominent example of procedural animation is ragdoll physics.

Sound

Although less common than the previous examples, procedural generation is also used to create game sounds. This will commonly be in the form of manipulating existing sounds. For example, sound can be spatialized, meaning it appears to be coming from a specific position when heard by the user.

At a stretch, short, one-shot sound effects may be synthesized, but due to the little benefit that it brings as compared to the amount of work needed to implement it, it's seldom used. It's simply much easier to load premade sounds.

Note

Sfxr is a small program that generates random sound effects from scratch. Its source is available. So, if sound synthesis interests you, it will serve as a good starting point. You can find the project at https://github.com/grimfang4/sfxr.

 

Benefits of procedural generation


We've looked at some of the key ways in which procedural generation is used in games. So now let's take a look at some of its most important benefits.

Larger games can be created

If your game world is hand-built, it's going to have size restrictions for a number of reasons. Every object needs to be placed manually, every texture/model needs to be handcrafted, and so on. All of this takes time and money. Even the largest handcrafted game's world sizes, such as those seen in The The Witcher 3: Wild Hunt and Grand Theft Auto V, pale in comparison to what procedurally generated worlds can achieve.

If a game utilizes procedural generation correctly, then theoretically, there is no limit to the world size. For example, No Man's Sky is a science-fiction game set in an infinite, procedurally generated galaxy. When you start to get really big maps however, hardware becomes a limiting factor. Areas that have been generated need to be saved to the disk in order to revisit them, and this quickly adds up. For example, to generate the biggest world possible in Minecraft, you will need around 409 petabytes of storage for the level data!

Procedural generation can be used to lower budgets

Making games is expensive. Really expensive. In fact, most AAA games cost tens, if not hundreds, of millions of dollars to make. With budgets that are this high, any option to save money is welcome. Procedural generation can do just that.

Let's say that we are working on a title that needs 100 brick textures. Traditionally, you'd have one of your artists create each brick. While they will have top quality, this will cost both time and money. Alternately, by utilizing procedural generation techniques, you can have an artist create a handful of resources and use them to generate however many resources you need to use.

This is just one example, and the same goes for modeling, design, and so on. There are pros and cons of using procedural generation in this way, but it's a valid option.

An increase in gameplay variety

If your game world is handmade, the experience that players have is going to be fixed. Everyone will collect the same items, the terrain will be the same, and as a result, the overall experience will be the same. The defining feature of procedurally generated games is that experiences differ. There is a sense of unknown to the game, and every time you play, there will be something new waiting that you haven't encountered yet.

An increase in replayability

Let's continue from the last point. If a game is linear, without any procedural generation, the challenge is gone after you've played the game once. You know the plot, you know where the enemies will be, and unless it has an amazing story or mechanics, there's not much reason why you'd want to play the game again.

However, if your game utilizes procedural generation, then the challenge is fresh each time the game is run. The game is always evolving; the environments are always new. If you look at the games that have the greatest replayability, they tend to be the ones that give the player the greatest amount of control. Most of these games will utilize some form of procedural generation to do so.

 

The drawbacks of procedural generation


As with anything, there are two sides to a story. Procedural generation brings a myriad of possibilities and enhancements to games, but there are considerations to be taken when implementing it.

More taxing on the hardware

As we now know, procedural generation is the creation of content through running algorithms. These algorithms can be intense and require a lot of computing power. If you develop a game that makes heavy use of procedural generation, you need to ensure that a regular consumer PC or console is able to meet its demands.

For example, if you choose to generate trees procedurally in an open world game, there's going to be a big load on the CPU and GPU whenever that area needs to be generated. Lesser PCs might not have the power to do so, and therefore, they may stutter.

Worlds can feel repetitive

Another potential drawback is the fact that worlds can feel repetitive. If you allow your game system to generate incredibly large worlds, but use few and basic algorithms to do so, you'll inevitably have a lot of repetitive areas being generated. Patterns and repeating areas will be very easy to spot, and this will diminish from your game greatly.

You sacrifice quality control

Computers may be faster at crunching numbers than us humans, but there's one thing that we're vastly superior at, and that's creativity. No matter how amazing the procedural algorithm is, you lose the human touch. The little changes and subtleties that a seasoned designer can bring to a project are sacrificed.

It also means that you can't guarantee the same gameplay quality to all players. Some players may generate a really great map that facilitates gameplay, while others may generate a map that actively prohibits it.

You may generate an unplayable world

In extreme cases of the previous point, a level that is completely unplayable may be generated. The risk of this happening depends on how well your procedural content is generated, but it should always be considered.

When generating a 3D terrain map, you may accidently generate a terrain that is too high for the player to climb, or blocks off an area that needs to be accessible. The same goes for a 2D map. Later in this book we'll be generating dungeon rooms randomly. So for example, we need to ensure that each room has a valid entrance and exit.

It is hard to script set game events

Continuing with the previous point, procedural generation is uncertain. If the entire world around you is generated exclusively procedurally and randomly, then it makes it almost impossible to script fixed game events.

Game events are pre-scripted events, and the nature of procedural generation is to create unscripted worlds. Getting the two to work together is a tough challenge. For this reason, games tend to use a mix of procedural generation and premade game development. With this, you get the fixed game events and moments that are needed to drive a narrative, and in between all of this, you create a unique and open world for the player to explore and interact with at their own whim.

 

A brief history of rogue-like games


Since we're going to implement what we are learning in a rogue-like, let's just take a second to look at their history. It's always great to understand the origins of the things that you are doing!

Rogue is a dungeon crawling game that was first developed by Michael Toy and Glenn Wichman and initially released in 1980. Every level of the dungeon was randomly generated along with the positions of the object within. Rogue defined the dungeon crawling genre and was the inspiration for many titles that followed. This is why we call games of this type roguelikes, because they are literally like Rogue!

Procedural generation has been a key element in roguelikes since their conception. This is why I chose the genre to introduce the topic. Together, we will recreate the iconic features that define the genre, and approach procedural generation with a very practical and hands-on approach.

 

How we'll implement procedural generation


At the very start of the book I gave a brief overview of each chapter and what we will be covering in it. Now that we've covered what procedural generation is, let's take a look specifically at some of the ways in which we'll be implementing it as we work towards creating our own roguelike game. This list is not exhaustive.

Populating environments

When we load the game for the first time our objects will be in fixed locations. We're going to start our efforts by fixing this, implementing what we've learned in this chapter about random number generation to spawn our objects at random locations.

At the end of this chapter there are a few optional exercises that include generating numbers within a collection of different ranges. I suggest completing them if you're not comfortable with it already, as we'll be relying on it to achieve this.

Creating unique game objects

One of my personal favorite aspects of procedural generation is the creation of unique objects and items. Knowing that there is a wide variety of items in a game is awesome. Knowing that the items don't even exist yet, and that the possibilities are limitless, is even better!

We'll start simply by initializing our object's member variables randomly, and move up to giving our objects unique sprites and properties. We'll also look at creating dynamic classes that can create highly unique objects from a single base class.

 

Creating unique art


Generating textures and materials from scratch using procedural generation is a very large subject. There are lots of ways by which this can be achieved. Traditionally, we use things such as Perlin noise as their basis function and then build upon it with patterns and colors. We're not going to go into this topic to this extent. Instead, we're going to use the built-in image processing features of Simple and Fast Multimedia Library (SFML) to create unique textures during the runtime.

Starting with a simple approach, we'll change image properties such as size, color, and scale to create a variation in the existing assets. We'll then use render textures to combine multiple sprite components on the fly to create unique assets for our enemies.

 

Audio manipulation


As with graphics, SFML offers a number of functions that allow us to modify sounds. Therefore, we'll use these to alter the pitch and volume of our sound effects to create variance. We'll then use advanced functions to create 3D spatialized sound, bringing depth to the scene through our audio.

Behavior and mechanics

It's not just the static items and resources that can be generated procedurally. To add more variance to our gameplay, we'll use some procedural techniques to create dynamic gameplay mechanics. Specifically, we'll create a system that will generate a random goal for the player, and present them with a random reward should that goal be achieved.

We'll also give our enemies some basic Artificial Intelligence (AI) in the form of A Star (A*)pathfinding, allowing them to chase a player through the level.

Dungeon generation

Towards the end of the book, once we're comfortable using Random Number Generator (RNG) with procedural systems, and with our game project, we are going to implement the defining feature of roguelikes; randomly generated dungeons.

I've mentioned a few times that procedural generation can be used to create theoretically never-ending game worlds. So, we're going to do just that. We'll implement a system where every room that we visit is generated randomly, and we'll give each floor a distinct feel using the graphics manipulation techniques we'll learn in later chapters.

 

Component-based design


Procedural generation is all about creating dynamic systems, objects, and data. Therefore, it makes sense that we want the most flexible game framework that we can have so that it incorporates this well. One of the ways to achieve this is through component-based design. Therefore, to end our work, we're going to take a quick look at it, breaking our project down into a more component-based approach.

 

The complete game


These are the major systems changes that we'll implement. There will be lots in-between, but these examples will cover the major mechanics and skills that we will be using. When we reach the end of the book, you will have a fully working roguelike with an endless dungeon that is randomly generated, randomly generated items that spawn in random locations, procedural textures throughout the dungeon levels, and random enemies, all implemented with a flexible component-based architecture.

You will not only learn the skills needed to implement procedural generation in your own games, but also see how they all work in the context of one-another. Isolated exercises are great, but nothing beats working on a real-world example.

 

Exercises


To enable you to test your knowledge of this chapter's content, here are a few exercises that you should work on. They are not imperative to the rest of the book, but working on them will help you access your strengths and weaknesses in the material covered.

  1. Using the std::rand() function with the modulo operator (%), for updating random_numbers.cpp to generate numbers that fall within the following ranges:

    • 0 to 1000

    • 150 to 600

    • 198 to 246

  2. Come up with a new way of generating a random seed during the runtime. There are lots of ways to do this. So be creative! In my solution, the first numbers were always similar. Find out whether you can generate a random seed that mitigates that.

  3. Have a look at your game collection and find out whether you can identify where procedural generation has been used.

  4. Which of the following are examples of procedural generation?

    • Loading a song

    • Ragdoll physics

    • Creating unique objects during the runtime

 

Summary


In this chapter, we learned that procedural generation is the creation of content by using algorithms. This concept can be applied to all digital media and is used in games to create dynamic systems and environments. Procedural generation brings larger games, variety, and dynamism; all at the cost of lesser control, and potentially lesser performance as it is taxing on hardware. Some examples of the most popular uses of procedural generation in modern gaming include terrain generation, texture creation, and procedural animation.

In the next chapter, we will take a look at the project that has been supplied with the book. As we learn to create procedural systems, we will be implementing them in a real game project, with the ultimate goal of creating a roguelike game, a genre that heavily utilizes procedural generation. We will review the game template, the SFML modules that we will be using, and get the project setup. Then, we will compile it on your system.

If you are familiar with C++ game development and have used SFML before, you may already be familiar with the concepts presented in the next chapter. If that's the case, feel free to skim through the chapter to get right into the programming in Chapter 3, Using RNG with C++ Data Types.

About the Author
  • Dale Green

    Dale Green is a computer programmer who has worked in a range of disciplines, from full stack web development to C++ programming in AAA video games. As a passionate video game programmer, Dale has worked on multiple AAA titles for both PC and console, self-published a PC title, and authored a book on Procedural Content Generation for C++ Game Development.

    Browse publications by this author
Latest Reviews (10 reviews total)
Le falta ahondar en conceptos pero es una lectura amena y apta para todos los públicos.
Was what I was looking for, clearly written
Fast service, grreat quality! Will buy from again in the future!!
Procedural Content Generation for C++ Game Development
Unlock this book and the full library FREE for 7 days
Start now