Procedurally generated levels - choosing your theme
** Originally published on the 31st of August 2018 **
This article is the 3rd article of a series. You can find the other articles here:
It's been a while since the first part of this series was published in this blog. I'll be posting the rest of the articles soon, hopefully keeping to the pace of an article a month, as I need to rewrite a lot of the original posts (and code) that were previously published elsewhere (and since removed). At the end I also hope to show how I "productize" the algorithm and publish it on the Unity Asset Store. Some parts (the ones that have to do with Unity Editor integration) have been removed from the code examples.
As previously mentioned, properly generating 2d levels is not easy. Most of the work is relatively hard, and requires some creative thinking. When I originally planned out my algorithm, I tried (as much as possible) to break it down to easy, manageable pieces, with increasing difficulty. You should expect these post to get more and more in depth, and harder and harder to follow. That being said, not today!
Today's post is about choosing a random theme for your level. When you think about it - choosing a ransom theme from a list of themes, is basically one line of code. However, we'll do it a bit differently. Instead of choosing from a list (or enum), we'll define a "Themes" folder, inside our assets folder. Our code will scan that folder, and choose a theme from it. We'll also add a placeholder Verify() function, to check the folder has everything we need, but we won't deal with it now. Doing it that way allows us to easily add as many themes as we want to the code-base, without recompiling, or writing any code. More specifically - we can give the task of adding more themes to the game to our art director, and not deal with it anymore.
In last month's post, we talked about choosing sizes, and we created the code that allows us to automatically choose an instance size. During our discussion of the code, we talked a bit about room sizes, but I forgot to add the room size code. Before we head on to choosing instance theme, let's fix that missing bit.
The code changes are quite simple. I created 2 new classes: Size and SizeDefinitions. Both class hold all the code that was previously related only to instance sizes and definitions. Each of these classes has 2 inheriting classes: one for instance and for room.
The usage of these changes is properly demonstrated in the additions to the SizeDefinitions class:
// Creates all of the custom room size definitions
RoomSizeDefinition roomSmall = new RoomSizeDefinition("Small", 3, 3, true);
RoomSizeDefinition roomMedium = new RoomSizeDefinition("Medium", 10, 10, true, 50, 50);
RoomSizeDefinition roomLarge = new RoomSizeDefinition("Large", 25, 25, true, 500, 500);
RoomSizeDefinition roomXl = new RoomSizeDefinition("XL", 30, 30, false, 2000, 2000);
And of course, I had to rename and replace the function GetListOfAvailableSizes() with GetListOfAvailableInstanceSizes() and GetListOfAvailableRoomSizes().
With that small bit of tech debt out of the way, we can continue with choosing our theme. As mentioned, choosing a theme should be a relatively simple function: choose a folder from a list of folders. For that purpose, we have to agree on where that folder is going to reside, and what will be in it.
The first part is easy. The "Themes" folder should be directly under out "Assets" folder. This is how it looks like in my current empty project.
What goes into a themes folder is much harder to answer. We won't answer that question right now. Suffice to say, that ALL elements regarding to the visual and behavioral elements specific to that theme, should be here. That includes (but definitly not limited to) sprites, scripts, sounds effect, music, etc. We'll revisit the folder later in our process.
For now, I'll create 2 empty folders under my "Themes" folder: DarkForest and Desert.
Here is the code for ThemePicker, a very simple class with one function:
public static class ThemePicker
public static string PickTheme ()
// Getting directories (themes)
string path = Directory.GetCurrentDirectory();
var info = new DirectoryInfo(path + "\\Assets\\Themes");
DirectoryInfo directories = info.GetDirectories();
// Randomnly choosing one
System.Random rnd = new System.Random();
int index = rnd.Next(directories.Length);
// Returning the name of the selected theme
Pretty simple, isn't it? Get the list of sub-directories under the "Assets\Themes" folder, choose one at random, and return its name. Obviously, we need to remember to name the folders with the themes' names.
To finish this all off, I added a new function to ProcGenInstance (our main class): GenerateInstance(). This will be the main function we'll be calling when generating a new instance. More on that function in the future.
public void GenerateInstance(string requestedSize)
Theme = ThemePicker.PickTheme();
And that's it! We have now chosen our theme.
In the next part of the series we'll discuss setting the background image of our theme (taken from the folder we just set up - "Themes"). Setting the background image will be the first step towards starting placing elements on screen for us to interact with.
Cya next time!