The Great Generator Shift
Hey there, time for another blog post! First things first, lets take a look at that todo list.
Oh wow! All of phase 1 is finished, and the phase is even longer than when we last saw it? This is great news! But wait, what’s this…?
Oh.
So yeah, I completely blew through my phase 1 todo list faster than I felt I had any right to. The thing I was dreading most, the interaction system upgrade, literally worked first try while on stream and I suddenly had to figure out something else to work on as to not end my stream after about 30 minutes. For the most part, everything on that list is in the game and functions perfectly (as far as I know), with the one exception being the dead player voice chat. I’m currently using a code package I found for voice chat but frankly I’m not totally certain how it works. For now, dead players are muted and I plan to write my own voice chat solution in the future, but that’s low priority for now, since when it comes to playtesting, play testers can just be in Discord together, deafened, then undeafen when they die to chat if they wish.
Great news, right? Finally I can move on to phase 2 and start making rooms, objectives, and enemies for a first alpha version, right?
Haha.
Ha.
Ha…
Yeah so I tried that, and even succeeded in a few instances. The game now has a handful of somewhat interesting rooms to help make levels a bit more diverse. As I was working on rooms, however, I kept running into small pain points. Since the beginning almost, I’ve wanted to have a system where you could have little subsections in the floor so that there’s distinct zones throughout the level. My solution to this was the sections system, which would allows the generator to have multiple tile sets to generate in sequence — frankly, an imperfect solution. Another pain point arose out of me playing games like Lethal Company and SCP: Secret Laboratory in my free time. Those games clearly have a system for having different doors take up doorways in their games. Technically I had this too, but it ran into the problem of what happens if one room prefers certain doors while another prefers different ones.
These two problems in particular kept nagging at me until yesterday, I finally caved. I rewrote the generator.
This was the gameplan I set out for myself, and as you can see, it’s already completely finished, and if memory serves, it only took about and hour and a half, maybe two hours. There’s several parts here, so I’ll explain each of them, starting with what I removed and why.
Firstly, tile sets. Tile sets were a good idea at first, but as my ambitions for the game grew, they very quickly became insufficient for the experience I wanted to craft. The tile set system allowed me to define a set of rooms to generate along with a weight for each room, as well as what types of doors to generate in that tile set. This seems like a sensible idea at first, but it has a few problems. The first and most dire problem with this system is the weights are kind of a lie, at least in the way I had them implemented. Since not all rooms are the same size, larger rooms have a higher chance of colliding with an existing room when they spawn, meaning they actually have a lower effective weight in this system, since if a room fails it simply starts the whole room spawning process over, new room and all. Theoretically, I could have fixed this problem and kept tile sets, but there were more issues. Tile sets with weights are prone to flukes leading to really weird generation. The way it was implemented, there’s probably a seed that would have lead to every room in the level being a staircase, making one really long line. While this kind of generation is extremely unlikely, I really didn’t like the idea that it was even possible, and things of that nature would still occur at a small scale every so often.
Sections are the other feature I removed from the generator. This is another idea that was interesting at first, but over time wriggled its vile tendrils into everything. Let me tell you, this system was the most painful to extricate from the generator, since basically every other part of it needed to interface with sections in some way, let alone other systems outside the generator that also cared about the section system. The goal of the section system, as I’ve already mentioned, was to create pockets of different zones within a single level. While the section system did do this, it was far too rigid in how it did. Sections were always generated in a linear manner; i.e. section 1 would lead to section 2 which would lead to section 3. This meant that a player would know that on this floor, you’d always need to go through section 2 to get to section 3, and that holds true for any floor that has multiple sections. This is fine for some floors and even fun, but having that be the case for every floor is very limiting design-wise. Even outside of that concern though, the fact that the section system split the generation up into distinct chunks made all other code going into the generator that much more unwieldy. Everything had to be an array. If I needed something to be an array for another reason outside of sections, then I had to figure out a different solution for that (cause Unreal Blueprints don’t have multi-dimensional arrays!)
So, lets talk about how I’ve rewritten and improved the generator. The first issue was those tile sets. They made it easy to quickly make a new floor, yes, but they left me with very little control over what a floor might look like without just making a tile set for each floor, which sort of defeats the purpose. The solution was to provide the generator with the parameters to build itself a deck of cards, in essence. Firstly, instead of giving the generator a tile set, I give it a list of hand picked rooms now. The important part, however, is that those rooms are not provided with weights, they’re provided with ranges. When the generator does its initial data handling step, it now randomly decides how many rooms of each type will be in the floor, within the specified ranges, throws these all into an array, and then shuffles it. Then, we sort of play a little card game. Whenever we generate a room, we effectively pull a card from the top of the deck and try to put it somewhere. If for any reason it can’t go where we try to put it, we just put it on the bottom of the deck and start over with the top card again. The generator will keep doing this until it either exhausts its deck or fails to spawn a room 50 times in a row, in which case it’ll completely start over, assuming the seed is dead. This means I have way more control over what rooms will be in the floor. For example, maybe I have a really big room that I only want to spawn twice at most. Now I can do that. Additionally, this new system solves the unique room problem. For those unaware, eventually the game is going to have a sort of secret hunting meta-game attached to it where you’ll need to solve puzzles that involve multiple runs through the game, and guaranteed unique rooms on certain floors was a hurdle that needed to be jumped in order to get there. Outside of that though, having the ability to have unique rooms is also a great way to have bits of lore that always show up on the same floor, including but not limited to audio logs and notes. Glad to report that the solution to that essentially ended up being a side effect of this spur of the moment decision.
The other big improvement to the generator is the socket system. This replaces the section system and is way more flexible than sections could ever hope to be while also being simpler in many ways. Basically the idea here is each doorway in each room has a tag that describes the types of doorways that are allowed to connect to it as well as the types of doors that can spawn there. In this case we’re playing a matching game — doorways only connect if they have the same socket. This has a few implications for the generator. Firstly, we can have sections that are not fully linear from each other now; it all just depends on what sockets exist where. This also means that subsections can create loops freely, so long as their sockets match with the doorways they’d loop with. Before, sections were not allowed to create loops with doorways from previous or subsequent sections.
An example of the new generator in action
The way I have the generator set up right now, it’s set to create 1 transitionary piece that turns into a section of rooms that don’t have doors between them. These pieces are colored here in the image as light and dark blue respectively. The fun part about this is that the transitionary piece was actually one of the first few pieces to generate, leading to a much more natural looking generation than the section system ever was.
You can also see here several of the new rooms I’ve been toying with — they’re the ones that are using the flat grey material.
This first room is a sort of test chamber or observation cell. The initial concept for this room was that I wanted to mess around with a room that had internal doors, and this type of room seemed like a perfect fit.
This is the other major room I’ve worked on so far. This room came about from a few ideas. Firstly, I wanted an excuse to add fall damage to the game (which now exists). The other reason was I thought it’d be cool to have a room with 2 internal paths that don’t connect to each other. Admittedly, this came with some complications. When I first made it, the upper doorways worked like any other doorway and would spawn rooms off of them. This had the consequence that if this room spawned early enough, it could lock most of the floor behind it if none of those rooms managed to connect back down to a spot where the players could access them. The solution ended up being to not allow those doorways to spawn rooms at all, but to crank up their loop creating chance to 100%. This means that as long as this room generates before the room that leads up to one of those doorways, it will always connect to it, so long as the sockets match. Luckily, I’ve also had the foresight to make this a generic solution that can be applied to any exit, so I can reuse this functionality in the future as well if I come up with another room that would need it.
Now that this overhaul to the generator is complete, perhaps now I can finally put my head down and just start making some rooms, objectives, and enemies. With this and the entirety of phase 1 finished, we really are getting close to the point where I’d feel comfortable saying the game is in its alpha state and be ready to start doing real playtests. Hopefully some time in the near future I’ll come on here with information on how to get involved. Stay tuned!