Great news everyone!
I've another update! Last time we met, I gave a general overview of how we currently design our levels, work the implementation of a hybrid handcraft/generated system.
In this update, I'll be covering the generated portion specifically.
To start let's talk how we initiate that sequence...
As mentioned before, most platforming levels will have a portion of their maps that may be generated. For those sections to exist, it relies on a number of conditional attributes that are present, including level type, size, space/planet, and player action. The most important one, in this development phase is player action. Some of you may be confused by that statement, so let me explain.
A player may have a number of objectives when they get to the platforming portion, which includes accessing locked doors. These locked doors serve as buffers between the handcrafted and generated sections. Therefore, when the player unlocks one of these doors, it initiates the level generator and creates that section. However, there are some problems with this approach. One of them being, if we tied such a function to the doors directly, we would need increase wait time for the doors to open, and the generator wouldn't have enough time over all to finish. Thats an immersions breaker through and through.
Stagger the generation, and have the first section generate the moment you get to the platforming section. Example: Planet A has the main section, and four locked doors, for sections A1 - A4. The player gets to the planet by rift gate, and in the background, section A1 generates. This is before the player unlocks the A1 door. When the player does get access to A1 and unlocks it, section A2 generates, so on and so forth. This staggered approach means we can afford those extra few seconds to ensure there are no mishaps and it doesn't fail a majority of the time.
The generator itself was a hurdle. I mean this is the fourth iteration of it! The previous one worked, but with so much progress having been made in other areas, and it's progress having become stagnant, it ultimately ceased to be operational and was incredibly outdated. We had a decision to make: attempt to salvage what we had or start from scratch.
With no time to waste, we considered a "why not both" approach. One of us, will have until the business week to see if we can salvage anything, while the other will devise a new system that is simpler and modular. In the end we opted to start from scratch. The old one was too far gone to waste any more man-hours in trying to make it work. But, this was not all a lost, because we were able to devise some similar utilizing what we learned from the previous setup. Iterative design. Love it, hate it, it's useful.
The new level generator is constructed in a way that breaks down the entire process into a set of custom events and a series of functions, attached to a sequence. The main custom events are:
1. Spawning the initial cell
2. Spawning level cells
3. Spawning the level rooms
4. Check overlaps
5. Branching The functions are rather straight forward, with things like, "get previous cell," or "check overlap."
The goal is to keep the process simple, efficient, optimized, and easily readable should the main designer(s) not be available.
So here's a breakdown of the generator. At the start some variables are set, like max number of rooms and cells, max number of in-between cells (how many generates before finding a new position), etc, and then it's initiated. Upon event play, an initial cell is spawned where the generator's origin location is. That cell is saved in a reference variable, and it's up, down, left, right components are checked with a line trace to see if they are colliding with any other cells or rooms. Should they not, they are added to a component array. Level spawn cells or level level spawn room is called, and and a number of cells between 5 and 15 or rooms between 1 and 5 are spawned, following a sequence of functions that:
1. Gets the previous cell/room and components
2. Check those components to see if they overlap
3. Conditional check for overlap, True: destroy the cell and start again False: continue the process
4. Check the number of inbetweens, True: call level spawn cells/room and find new random position to branch False: continue process until number is reached
5. Continue process until total number of cells/rooms are reached.
We will continue on in the next part of this feature. If there are any questions, critiques, feedback, etc don't hesitate to drop a line!
Be sure to subscribe to our newsletter and follow on Twitter.