Our lead designer and programmer Ian takes you behind the scenes with his latest level generation tweaks...
Posted by Mode7Games on Nov 30th, 2010
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:
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:
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;