I liked the technique Spelunky used to generate the levels in the game, and I want to adapt it for a 3D space, so that I can use it to help me design something in that 3D space. I'm just not sure how to approach this kind of problem. I feel like a direct translation for this specific approach isn't possible, but I still want to have something that feels similar, with the same sort of winding path.
1 Answers
This is an interesting question due to some of the challenges that arise when you start moving algorithms into higher dimensions.
Issue 1: Main Paths Occupy Little Volume
Let's start with a simple mathematical observation. The level generation algorithm works by computing a random path from the top row of the world to the bottom row of the world. At each step, that path can either move left, right, or down, but never takes a step back onto where it starts from. Assuming these three options are equally likely, the first step on a particular level has a 2/3 chance of staying on the same level, and each subsequent step has at most a 1/2 chance of staying on the same level. (It's 50%, ignoring walls). That means that the expected number of tiles per level is going to be at most
1 × (1/3) + (2/3) × (1 + 2) (since there's 1/3 chance to move down immediately, otherwise (2/3) chance to get one room, plus the number of rooms you get from a random process that halts with 50% probability at each step)
= 2.5
This is important, because it means that if your world were an n × n grid, you'd expect to have only about 2.5 "used" cells per level in the world for a total of roughly 2.5n "used" cells on the path. Given that the world is n × n, that means that a
2.5n / n2 = 2.5 / n
fraction of the cells of the world will be on the main path, so n has to be small for the fraction of the world not on the main path to not get too huge. The video you linked picks n = 4, giving, a fraction of 2.5 / 4 = 62.5% of the world will be on the main path. That's a good blend between "I'd like to make progress" and "I'd like my side quest, please." And remember, this number is an overestimate of the number of path cells versus side-quest cells.
Now, let's do this in three dimensions. Same as before, we start in the top "slice," then randomly move forward, backward, left, right, or down at each step. That gives us at most a 4/5 chance of staying on our level with our first step, then from that point forward at most a 3/4 chance of staying on the level. (Again, this is an overestimate.) Doing the math again gives
1 × 1/5 + (4/5) × (1 + 4)
= 1/5 + (4/5) × 5
= 4.2
So that means that an average of 4.2 cells per level are going to be in the main path, for a total path length of 4.2n, on average, if we're overestimating. In an n × n × n world, this means that the fraction of "on-path" sites to "off-path" sites is
4.2n / n3
= 4.2 / n2
This means that your world needs to be very small for the main path not to be a trivial fraction of the overall space. For example, picking n = 3 means that you'd have just under 50% of the world off the main path and available for exploration. Picking n = 4 would give you 75% of the world off the main path, and giving n = 5 would give you over 80% of the world off the main path.
All of this is to say that, right off the bat, you'd need to reduce the size of your world so that a main-path-based algorithm doesn't leave the world mostly empty. That's not necessarily a bad thing, but it is something to be mindful of.
Issue 2: Template Space Increases
The next issue you're run into is building up your library of "templates" for room configurations. If you're in 2D space, there are four possible entrances and exits into each cell, and any subset of those four entrances (possibly, with the exception of a cell with no entrances at all) might require a template. That gives you
24 - 1 = 15
possible entrance/exit templates to work with, and that's just to cover the set of all possible options.
In three dimensions, there are six possible entrances and exits from each cell, so there are
26 - 1 = 63
possible entrance/exit combinations to consider, so you'd need a lot of templates to account for this. You can likely reduce this by harnessing rotational symmetry, but this is an important point to keep in mind.
Issue 3: Getting Stuck
The video you linked mentions as a virtue of the 2D generation algorithm the fact that
it creates fun and engaging levels that the player can't easily get stuck in.
In 2D space, most cells, with a few exceptions, will be adjacent to the main path. In 3D space, most cells, with a few exceptions, will not be adjacent to the main path. Moreover, in 2D space, if you get lost, it's not hard to find your way back - there are only so many directions you can go, and you can see the whole world at once. In 3D, it's a lot easier to get lost, both because you can take steps that get you further off the main path than in 2D space and because, if you do get lost, there are more options to consider for how to backtrack. (Plus, you probably can't see the whole world at once in a 3D space.)
You could likely address this by just not filling the full 3D space of cells with places to visit. Instead, only allow cells that are one or two steps off of the main path to be filled in with interesting side quests, since that way the player can't get too lost in the weeds.
To Summarize
These three points suggest that, for this approach to work in 3D, you'd likely need to do the following.
- Keep the world smaller than you think you might need it to be, since the ratio of on-path to off-path cells will get large otherwise.
- Alternatively, consider only filling in cells adjacent to the main path, leaving the other cells inaccessible, so that the player can quickly backtrack to where they were before.
- Be prepared to create a lot of templates, or to figure out how to use rotations to make your templates applicable in more places.
Good luck!

- 362,284
- 104
- 897
- 1,065
-
This is really interesting! Maybe I can create a bit of diversity by making the path occasionally branch off, or "pool" into a larger hollow space, which can also have branches off of it. – chexo3 May 05 '20 at 22:23
-
Also the square cube law is annoying as usual. It's a good thing I'm not trying to make this in 4D space. I mean now I kind of want to, but as this is code is to help me design a Minecraft base, I'm limited to 3D, specifically sections of cubic voxels. – chexo3 May 05 '20 at 22:26
-
Also this technique with the pooling and the extra branches seems like it would create a tree-like structure. – chexo3 May 05 '20 at 22:31
-
1If you're looking to create spanning trees of a space, there's plenty of work done into things like randomized DFS, randomized Kruskal's algorithm, etc. Maybe looking into maze generation would be a good starting point? (Also, yes, it's good you're not in 4D. After writing this I realized that the fraction of space that's occupied on expectation is O(d / n^d). – templatetypedef May 05 '20 at 23:34
-
Thanks again for all this! Revisiting this question, you've written a lot of useful stuff here. Seems like in summary: Larger space/more cells is problematic for this approach, regardless of whether cells are added with a large grid, or a grid with more dimensions. This approach is similar to a spanning tree or maze generation. The main issue is that as size of the space being generated increases, the ratio of cells on the path vs. cells not on the path gets unbalanced. I really ought to set up Processing or a game engine or something to test different approaches. – chexo3 Jun 05 '22 at 01:02