@ : ProcGen AT ruggnar DOT com
Ruggnar is a platformer set in dark, gloomy places, where the player controls the dwarf Ruggnar through the dark as he searches for treasure. In this game, there are several game modes: Story mode, with handmade levels; and Random mode which uses procedural generation. In this article, we'll focus on Random mode. In it, I'll try to explain my method for generating levels as clearly as I can.
Development of Ruggnar began on September 22, 2016. Just a few days later I made the decision to attend a monthly local indie games event in Metz, France. During my first participation, I was invited to work on a level generator and Spelunky was the game given as an example.
I really like Spelunky. I knew that the levels were generated, but I never looked into the subject before this meeting. I found an article about the method used in Spelunky, and after reading it was inspired to implement one in Ruggnar.
In a generated level for Ruggnar I need both a starting and end point, in a closed space.
I chose to work on a grid with variable dimensions, made up of sections.
I decided to create every section by hand and give each section the same dimensions. I did this to be sure the player can properly complete a section.
Below is an example :
Every section has its own layout, with grounds, walls, decorations, hazards and coins.
It also has a starting point, a treasure as the ending point, a checkpoint, a key and a candle.
A section is characterized by its borders, with each border being a type of exit.
When the generator puts a section on the grid, it checks that the borders of the new pieces are compatible with the neighbours borders.
In the previous picture, there are grayed border cases. These are the exits, the open walls of the section.
Some example of exit :
|Type 1||Type 2||Type 3||Type 4||Type 5||Type 6|
A section is made of 4 borders, so we must pick 4 exits: 2 vertical and 2 horizontal.
The number of sections to make increase quickly, based on the number of different kinds of exit :
|Vertical exits (v)||Horizontal Exits (h)||# of Sections (s)|
The formula is : s = (v · h)²
It's important to create every section based on the exits you've chosen, or you'll face holes in your grid. on the other hand, if you only make the required sections, you'll end up with repetitive levels. That's why it's a better move to make several versions for each exit configuration.
In Ruggnar, I have another way to generate variety. In the previous part, I spoke about what we have in a section. Among all the sections in my final grid, I chose a starting and an ending point.
Hazards have a probability of occurrence, from 0 to 100%. The number of coins, candles, keys and chekpoints is based on the size of the final grid, so the same level section will quite be different from one game to another!
The game zone is a grid where each case is a section. When the process is over, the level is created with the sections of the grid. For the prupose of this article, I'll work on a 5x5 grid.
To start generation, I put some blocked sections on the grid. The grid won't be a simple square, but as some parts will be impassable, the structure of the level will be less straight, less predictable.
We can see 2 blocked sections in black. The walls will be filled in with no way to reach the blocked section.
For each unblocked section, the generator searches for compatible sections (among all the sections available) with direct neighbouring walls (North, South, East, West) :
- - Each wall must be compatible with its adjacent walls
- - The border of the grid will have closed walls. The area must be a closed one.
## New addition May, 11th ##
If you watch carefully the generated level on next image, you'll notice redondant areas.
To avoid this behaviour, before adding a section, I check how many times it has been used in the level. Ideally, none.
The idea here is to have a level with only distinct sections.
On a single level, I have all the sections I need to create the map.
But with the new game mode, the player enters a castle with 10 floors, I have to check, floor by floor with the same technique to have a castle without repeating sections.
So, I check first the sections never placed, then placed once, twice, and so on, as long as I don't have a compatible section.
Now with this system, the levels are even more twisted.
Here we can see that 1 more section was blocked on during generation. Notice that the walls are identical side by side.
This is a real level, based on the grid.
The sections have been filled with the tiles and decorations!
If the process were to be stopped here, and the content filled, we'll take a risk to lock the player in an area he can't complete (no exit reachable, or not enough keys). so the process has to include a flood fill algorithm to find every closed area.
Each color shows a distinct closed area. Not counting blocking sections, we have 11 red, 9 blue, and 2 green.
For the player to have the biggest playground, I keep only the biggest area. I'll clean up the grid and keep only the red area.
## New addition january, 10th 2019 ##
When there are more than one area, the algorithm, now, keep tle largest, like before, but also keep the second largest area (only if it meets some minimal size requirements).
Without any modification, the player couldn't finish the level. Pieces or the exit could be in the other area.
The idea here is to connect the 2 areas, using some teleportation items. A door is placed in each area, so the player can go rom an area to the other.
My process is almost complete! Now I generate the decorations and hazards to finish off the level:
With so many possible arrangements, Ruggnar has thousands of unique levels!
With Random mode, you have access to a lot of levels to play. Every game will be different than the previous, and the challenge will be renewed. This article will be updated later as Random mode in Ruggnar evolves.
Ruggnar is in Early Access on itch.io. If you wish to give a boost, it could really help!
You can also wishlist the game on Steam
If you have questions, comments, or want the latest news on Ruggnar, find me on Twitter