Post news Report RSS Frozen Synapse: Procedural level generation

Our lead designer and programmer Ian takes you behind the scenes with his latest level generation tweaks...

Posted by on

The levels produced by our generator look like this:


They are a bunch of pre-made rooms thrown onto a playmap and rotated and messed around with a bit, basically. It’s a good generator, and I’ve never had any complaints about the terrain itself (although I’ve had plenty about the unit placing!). Our levels are pretty unusual in how open they are, and I hope you can see that from the picture above – many windows have good coverage of a very large proportion of the map.

I’ve been meaning for some time to produce an alternative level generator, which produces maps which are tighter – maybe a bit more like a Counter Strike map than a Tribes map for example.

Almost a year ago the infamous Lyx produced what is by a long way my favorite human-designed map – we in fact ended up using it for our first demo to PC Gamer. Don’t tell him that though. This is the map:


(I call this “Lyx1″ – I don’t think he gave it a name himself).

As you can hopefully see, this is a much tighter map with some superb deathmatch-esque flow to it. There are three main “routes” between the left and the right, producing a very replayable, differentiated experience.

I sat down yesterday and said to myself: “I want to make a generator which makes maps like that.” So I sat down and tried it. (You may want to skip down to the bottom if you aren’t interested in stories about generative content algorithms).

I started off with an algorithm which I use in the existing generator, which goes something like this.

Start off with a blank slate of the right size, and pick a random corner – top left, top right, bottom left, or bottom right:


Create a randomly sized room-shaped block there:


Partition the rest of the area into two rectangles (the cyan and blue rectangles here):


Recursively repeat in those areas:


And stop when your boxes are getting too small for rooms. Running the algorithm gives something like this:


First off we add some walls. Now we have to make sure every room is accessible from everywhere in the map. To do that, we start off with the top left room, and make a doorway to each adjacent room. Then we go to those rooms and add doorways to any rooms adjacent to them. We also make sure to add a door to the outside somewhere. Running the algorithm produces this:


Most of the hard work has been done. Now we add a few more random doors and some windows around the place:


Finally, we add some boxes for cover. There probably aren’t quite enough boxes on this particular map, and the algorithm for putting boxes outside doesn’t produce very pretty results yet… but I’m almost there. The finished level:


I admit to having picked this map as it looks especially nice, but the truth is that the vast majority of maps generated are very effective. This kind of map produces quite a different FS experience, and I’m excited to get it out there. I think the multiplayer mode that will most benefit is Disputed, but I think it’ll be good for some old fashioned Extermination too.

Here are some other maps the algorithm has produced:





And, for anyone who’s interested in such things, here’s the settings object which gives some insight into which elements of the generator can be easily tweaked. Bin is going to be using these to make some heavily differentiated single player maps:

new ScriptObject(csSettingsStandard)
{
minZoneSide = 100;
maxZoneSide = 300;

stopZoneSide = 125; // stopZoneSide mst be more than minZoneSide
minGap = 60; // basically the smallest sided new area in the initial recursion

outsideWallWidth = 10;
insideWallWidth = 8;

minEdgeWidthForDoor = 60;
doorWidth = 30;
useMiddleDoors = false;
doorEdgeSpace = 20;

windowWidth = 32;
windowDif = 3;

doorZoneSize = 40;

outsideDoorChance = 0.5;
outsideWindowChance = 0.4;
extraDoorChance = 0.3;
windowChance = 0.43;

minRoomWidthForBox = 80;
chanceForBoxInRoom = 0.6;
minEdgeWidthForBox = 80;
minBoxSurroundingSpace = 30;
minOutsideBoxSurroundingSpace = 0;
minBoxWidth = 25;
maxBoxWidth = 110;
boxHackFromWall = 10;
boxWidthRectangleTriggerSize = 50;
boxWidthRectangleSize = 40;
chanceForMultipleBoxesInRoom = 0; // this code doesn’t work so leave this at 0
boxRightAtWallChance = 0.25;
roomSizeGuaranteesBox = 150;

outsideEdgeBoxChance = 0.1;
outsideBoxDepthRange = 60;
outsideBoxTooClose = 20;
maxOutsideBoxWidth = 50;

lightChance = 0.7;
};

Post comment Comments
spellman23
spellman23 - - 127 comments

Pretty neato.

Maybe something to add would be a way to seed initial rooms. That way you could do something like force a two-base look, or sprawling rooms from the center and both teams start on the outside, using clever initial boxes.

Reply Good karma Bad karma+1 vote
BrainCandy
BrainCandy - - 141 comments

Love it! Procedural generation is hard to implement but saves a lot of time for sure! We are designing all our levels by hand and it is sometimes really a hassle to make everything coherent and that fits within the storyline.

Your solution offers a wide variety of gameplay situations that would be impossible if they had been made by hand. Great stuff.

Reply Good karma Bad karma+1 vote
dsi1
dsi1 - - 157 comments

Amazing, exactly the kinds of maps I was hoping for!

Reply Good karma Bad karma+1 vote
SolidFake
SolidFake - - 1,200 comments

looking good
will the game also includde a the level generator/editor?

Reply Good karma Bad karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: