Wave Function Collapse

For my graduation work at DAE, I was tasked with researching and implementing the Wave Function Collapse (WFC) algorithm to generate game levels. For this project I researched WFC in both 2D and 3D space and as a result created the following research questions:

- What are the necessary modifications to the 2D Wave Function Collapse Algorithm to extend it to 3D space?
- What is the impact of adding extra adjacency constraints to the 3D Wave Function Collapse?

To answer these questions, I created a Unity project and started implementing WFC in both 2D and 3D. After testing these implementations, I felt confident in being able to answer these questions and write my findings and conclusions in my research paper. In the following paragraphs I would like to give an insight on how WFC works and describe my approach in this project. Additional information can be found in my paper, which can be found below.


Important terms

Before delving into the algorithm itself, I would like to explain three terms that are used for WFC.

1. Entropy: The amount of chaos in a cell. This is chaos represents how many possible states the cell can be in.

2. Adjacency constraints: These are rulesets that the algorithm must follow when generating the output map (i.e., colour adjacency for 2D maps).

3. Module: A module represents one possible end state for a cell . A module typically contains the sprite or model for said state and info that might be required by the adjacency constraints.


General WFC

Wave Function Collapse takes a set of tiles as input. These tiles for 2D and 3D WFC are sprites and 3D models respectively. The algorithm uses the given adjacency constraints to generate the output map. Multiple adjacency constraints can be stacked and combined to tailer the outcome map to the desire of the user.

The final result of the algorithm is represented as a grid of cells, which also represents the "wave" that will ultimately get collapsed. These cells initially are all in superpositions, meaning that their final state is not yet decided. To collapse the wave, WFC loops over these steps:

1. Observation: Start by looking for the cell with the lowest entropy. Collapse the cell into its final state using constraints or pure randomness. This final state is one of the still possible modules left for this cell.

2. Propagation: Relay the info of the collapsed cell to its neighbours. Discard modules that can no longer fit and propagate this info to those neighbouring cells. Repeat this until all cells that need to discard modules have done so.

3. Search for the cell with the lowest entropy. Check if one has been found.
     a. Cell was found; repeat the loop from step 1.
     b. No cell was found; stop the loop as the wave has collapsed.

When the wave is fully collapsed, all cells have their final state, and the map can be generated and used. A step-by-step guide on how this was implemented and the testing methodology and results in can be found in my paper.


Personal takeaways

Finally, I would like to talk about my experience and takeaways regarding this project.

Suffice to say that I learned a lot about procedural content generation in researching WFC and had a look at a lot of different approaches towards it. It is amazing to see how much replayability can come with a (relatively speaking) simple content generator. Throughout this project I also found myself becoming a lot better at preparing and outlining classes or functions before starting to program them. This really helped in keeping a clear oversight of the project.

I also definitely learned some things about myself that I had not yet realized before. First of all, I really enjoyed researching atopic and gradually becoming more and more familiar with it. I did realize that I should sometimes rely a bit more on my gathered research instead of delving in headfirst and creating something from scratch.

Secondly, I learned the difference between speed and efficiency. There were some moments where I took shortcuts in order to save time, but had to come to the realization that I lost even more time afterwards. I.e., I created some 3D models that were very basic and not very modular. This made it difficult for the algorithm to generate good levels and cost me a lot of time spent debugging. Suffice to say that it is often better to do something correctly rather than fast.

Finally, I became a planner for this project. Throughout my years as a game programmer I have often procrastinated and disregarded planned project outlines or structures. For this project I was required to plan the entire scope of the case study and paper and I decided to try to stick to it as much as possible. This helped me so much with stress and keeping my project on a correct course, that I am sure that I am on my way to become a planner rather than a procrastinator.

To close this project off, I would like to give a major thanks to my supervisor Flor Delombaerde for guiding and helping me throughout all the project.