Yesterday was my least productive day of the challenge – after work, I spent some time with old friends. The stress of spending all of my waking hours staring at a computer screen was starting to get exhausting, so I took a break for an evening.
However, I spent two hours late last night polishing my level generation algorithm!
Rogue Space Marine is a combat-focused game, so the level generator has only one job: reliably produce levels that create opportunities for fun and interesting combat. In practice, this means I need a mix of open spaces and obstacles/cover. Rooms need to be stitched together into a navigable level, and computer terminals need to be placed in interesting spots so that the player has to fight to get to the objective.
With this in mind, and with the primary goal of creating interesting spaces for combat, I decided to model my level generator after Derek Yu’s ingenious algorithm from Spelunky. Spelunky’s levels always feel as if they were hand-created, even though you get a radically different randomized experience each time you play. This is because Derek Yu made his algorithm work on a mixture of hand-crafted and randomized elements. Each room shape is selected from an assortment of hand-crafted prototypes, and the interior of those rooms are filled with randomized obstacles and decorations. Rooms are randomly selected and stitched together in a logical pattern that ensures that all of Spelunky’s levels are playable, winnable, (and more importantly), fun.
To implement this in my game, I create room prototypes and store them as long strings of characters. Each character represents a single tile in the room. The assortment of characters tell the level generator what kind of tile to place in the corresponding location.
I made a little Excel spreadsheet that allows me to quickly draw room layouts, automatically color-coding the characters as I write them, and automatically generating appropriately formatted strings that can be imported directly into the game. Each room is 11 x 11 tiles in size, so the room strings are all exactly 121 characters in length.
Here is the section of the Excel file where I draw the room.
o = wall
D = decoration (100% probability)
d = decoration (small probability)
t = computer terminal (small probability)
red areas = possible hallways, depending on level layout
black areas = outside of the room
w = possible wall / obstacle (small probability)
The Excel file then uses some logic to create the following list of characters:
N = north entrance (populated only if a hallway exists to the north)
S = south entrance (populated only if a hallway exists to the south)
W = west entrance (populated only if a hallway exists to the west)
E = east entrance (populated only if a hallway exists to the east)
. = floor tile
, = outside of room (empty space)|
e = possible wall location (populated only if a hallway does not exist to the west)
Finally, Excel parses the table data into 6 different strings which represent all 6 possible room configurations. Normal (as drawn), rotated 90 degrees, rotated 180 degrees, rotated 270 degrees, vertically mirrored, and horizontally mirrorred.
A single room string ends up looking like this:
The game’s level generator script reads out this string and places the tiles in the correct spots, generating random tiles based on probabilities. Then, the room is populated with appropriate enemies on empty floor tiles. Finally, the level is stitched together from multiple rooms using hallway logic.
Here are a few examples that were created by using the single string that appears above.
With even just a handful of rooms prototypes, thousands of level layouts are possible due to the randomized elements. Most importantly, I have a high level of control over how gameplay works within the rooms because they are mostly hand-designed, with some randomized elements to keep things interesting.
Thanks for reading!
Previous Rogue Space Marine Posts: