Website powered by

Procedural 3D Cave Generation: Cellular Automata

Software: Unity
Time: 12 Hrs

Objective: This is my first attempt at creating a procedurally generated level. My Goal was to make a 3D cave system that was visually interesting and navigable to a player. I was inspired by Deep Rock Galactic; An FPS where you are sent into asteroids in space to mine materials and complete objectives while fighting hordes of alien enemies. While Deep Rock uses a form of Occupancy Related Extension to generate their caves, I wanted to see what I can do using a different method. Most examples I saw for creating levels with cellular automata were in 2D and I wanted to see what this method could do with 3D.

Challenges: Finding a set of parameters that fit my goal. Changing one value dramatically changed the level that was generated. In addition these values also were in relationship to one another. If I was satisfied with one (A) of four values (A,B,C,D) , and changed another two (B,C), the value I was originally satisfied with (A) may not give me the same result that I expected in relation to this change.

Lessons Learned: -Procedural Level Generation requires lots of testing and iteration, just like anything else in game design.
-If a designer wants to use Procedural generation, it is 100% necessary to ask, "will this solution save time vs creating the assets organically?" & "Does this solution fit my project?".
-Procedural Generation is challenging
- In the end I don't feel like I succeeded in everything I wanted to do, but I may eventually come back to this and build upon my work. Regardless I did learn a lot from this and wanted to showcase it.

Sources Used: (2D cave generation cellular automata)
https://gamedevelopment.tutsplus.com/tutorials/generate-random-cave-levels-using-cellular-automata--gamedev-9664

Some of the end results. End result images at bottom of project.

I used a coroutine to show generation in real time.  This is when I started to get desirable results with the values I input.

I used a coroutine to show generation in real time. This is when I started to get desirable results with the values I input.

Step 1 was to generate an array of an object using 4 parameters. This is the result of that random generation.

Step 1 was to generate an array of an object using 4 parameters. This is the result of that random generation.

This is the code I used for step 1. Generate a 3D array using Booleans and random value. Then set the level bounds height, width, and depth.

This is the code I used for step 1. Generate a 3D array using Booleans and random value. Then set the level bounds height, width, and depth.

This one example of my results after getting the cellular automata working.  There are many instances of cubes that have too many holes or the geometry was too random.

This one example of my results after getting the cellular automata working. There are many instances of cubes that have too many holes or the geometry was too random.

This function counts the neighbors next to the alive cubes and returns a count value to be used in another step.  This also checks if the cubes are within bounds of the area I set in step 1.

This function counts the neighbors next to the alive cubes and returns a count value to be used in another step. This also checks if the cubes are within bounds of the area I set in step 1.

Step 3 is to run the automata simulation by checking over the old map that was created in step 1.  From there it compares my "death limit" and "birth limit" to the count value in step 2.  These new values control if new blocks are to be generated.

Step 3 is to run the automata simulation by checking over the old map that was created in step 1. From there it compares my "death limit" and "birth limit" to the count value in step 2. These new values control if new blocks are to be generated.

I realized at this point the values were in relation to each other and changing one dramatically altered the results of the rooms.

I realized at this point the values were in relation to each other and changing one dramatically altered the results of the rooms.

Because every value was dependent on other values, I had to document my results.  In the end few value sets fit my goals for the project and I labeled what those rooms could be used for.  These are only some of the test I performed.

Because every value was dependent on other values, I had to document my results. In the end few value sets fit my goals for the project and I labeled what those rooms could be used for. These are only some of the test I performed.

I graphed the data from the chart.  The X axis represents the geometry inside the level, while the inner graph is the amount of gaps in the outer mesh.

I graphed the data from the chart. The X axis represents the geometry inside the level, while the inner graph is the amount of gaps in the outer mesh.

Here are some examples of rooms that had interesting inner geometry and had entrances and exit points. 1/2

Here are some examples of rooms that had interesting inner geometry and had entrances and exit points. 1/2

2/2

2/2

These are 3 of the more interesting levels generated.  I created a gem for a place holder for minerals using a function that checks if there is space next to the cubes. 1/3

These are 3 of the more interesting levels generated. I created a gem for a place holder for minerals using a function that checks if there is space next to the cubes. 1/3

2/3

2/3

3/3 (If a player were to stumble across this room they would feel greatly rewarded.)

3/3 (If a player were to stumble across this room they would feel greatly rewarded.)