Procedural (Side) Missions

It's been a while since I last posted, a lot of things have changed in the interrim. Not to the game, just my general situation. First of all, I've moved down south, so that was a biggie. I've been waiting to start a new job so that had been killing my energy, I was just waiting to start so I would lounge around all day just existing in this weird limbo mood. I've been doing artwork for an indie title, which has been a priority. Also, XCOM2 War of the Chosen came out, which didn't help either.

What I've been working on, on and off, is a form of procedural level generation for AGGRESSOR.

Hear me out. I originally wanted to hand craft every level, in fact I thought it just wouldn't work if it wasn't. But after doing a few missions I realised how much time and energy it took to create just one mission, and given how little time I will have to work on the game.. I needed to either have a very short game, or get creative and work smart. My solution, thus far, is to hand craft the significant levels. The story beats, the levels that have a special visual flare or theme to them. And then let the game switcheroo the interrim levels, the connecting segments ect.


I looked into how procedural generation was done in Spelunky, which was interesting. Basically, they had a grid of squares, and they generated a path through it. Then, they'd choose what type of room it'd be based on if there was a room above, to the side, ect. Then they'd pick a number out of a hat, and use that configuration. Every configuration is hand crafted, but which one the room will use is randomly selected. I liked this; the "chunks" were hand crafted, but they were just arranged in a random order. I've tried to replicate this.

So, each of my "prefab" segments is a consistent size. The script places these big empty squares one-by-one, picking a random direction each time (but never back, i.e left). Then, a second part kicks in that determines what kind of room each square should be. If it has a connection left and right only, it's a corridor. Left and up, a corner. All sides, a 4-way intersection. Only one, a dead end. The first and last tile will always be dead ends. Then, finally, a third pass replaces these temporary squares with prefab segments, which contain all the collision, object locations ect needed to be gameplay functional.

I had to first define each prefab, defining where it's collision and spawns are. I created a script which would "bake" all this data quickly out to a text file, because doing it by hand was an insane amount of tedious work that no rational human being would attempt. Then, I had to create the logic that would apply the collision, but rotate it all to fit the rotation of the prefab, so if a piece was turned 90' it's collision wouldn't be 90' the other way still.

This was an absolute ball ache to figure out, but it's working now.

One of my biggest hurdles has been figuring out how to do enemy movement grids. See, usually you build a level and set the width/height to be just enough to include all your stuff. Then, in-game, when the grid is made, it fits neatly over and stops at the edges. The problem is, these generated levels vary in width and height per generation.

The dirtiest solution was to make the room just huge, like bigger than the generation could ever fill. The problem there is, though, all of the enemy move and lighting calculations will be using this collosal size and that'll eat memory.

The better solution was to dynamically resize the level to fit all the geometry, but the problem is Game Maker won't let you resize a room that's already open. Greaat.

My solution was to instead split generation into two parts. It starts in a "canvas" room, a temporary room just used as a sort of notepad. The first lays out the squares, chooses their type and rotation, but stops there. This is all it needs to do, figure out the layout and size of the level. It saves their location and rotation to a data structure. It then measures how long and tall the level is, and sets the width and height of the actual mission accordingly. It then moves over to the actual mission level, replaces the squares, then turns them into usable prefab segments.

This way, the final mission is always exactly the right size. It fits neatly, tightly, around the generated layout. This is important, because Game Maker will not let you create a grid outside of the room. This minimises wasted grid space and hopefully will keep the overhead down.

There are 5x5 prefab segments so far, and I'm in the process of prettying them up. Each segment is a collection of rooms, so I'm hoping that any repetition won't be too noticable. I can go back and add more segments if it's too noticable.

So, in summary. The system currently can build little level vignettes, short connecting missions that are just gameplay hits with minimal story. These are to pace out the critical missions, and ensure the game doesn't abruptly end (but hopefully, used sparingly enough not to feel like padding).

My go to example is XCOM; how alien abductions, guerilla ops and UFO landings are all randomly generated while story missions have crafted objectives and events. If it wasn't for the abductions and landings, it'd be a short and linear game.

Anyway, we'll see how this works out.

- Rob

Comments

Popular posts from this blog

A productive day!

Moveset Expansion (and controller support!)

Tile Bleed & Looking at Art Style (Again)