My thesis here is that a small set of random-number based heuristic techniques is actually a much shorter and more sustainable path to good site maps, than fine-tuning a more general purpose algorithm (e.g. advanced perlin noise, geologic simulation) would be.
Put another way, rather than try to solve board generation from first principles or in frequency space or in any other way that I find hard to think about, instead I will focus on building a set of operations that I understand in the problem domain. Things like, roll every square on or off.
Erode terrain.
Grow terrain (dilate).
Draw random lines that represent tunnels.
Make sure the spawn area is filled in.
Trim corners.
Flood fill to eliminate islands.
So if you take a look you can see each step is just an action added to a sequence. The individual actions make sense and are individually configurable. Here's one that makes forest maps:var actions:Vector.= new Vector. (); var noise:NoiseAction = new NoiseAction(_map); noise.minX = 1; noise.minY = 1; noise.maxX = _map.width - 2; noise.maxY = _map.height - 2; noise.chanceToFill = 0.5; actions.push(noise); var erode:GlobAction = new GlobAction(_map); erode.filter = [true, false]; erode.fractionOfTotalSquaresToGlob = 1.0; actions.push(erode); var dilate:GlobAction = new GlobAction(_map); dilate.filter = [false, true]; dilate.fractionOfTotalSquaresToGlob = 2.0; actions.push(dilate); var tunnel:Tunnel = new Tunnel(_map); actions.push(tunnel); var spawnRect:Rectangle = new Rectangle(1, 1, 4, 3); var spawnArea:SetRectangleAction = new SetRectangleAction(_map); spawnArea.minX = spawnRect.x; spawnArea.maxX = spawnRect.right; spawnArea.minY = spawnRect.y; spawnArea.maxY = spawnRect.bottom; actions.push(spawnArea); var trim:TrimCornerGaps = new TrimCornerGaps(_map); actions.push(trim); var floodFill:FloodFillMap= new FloodFillMap(_map, 3, 3); actions.push(floodFill); var floorFixer:FloorTileRectifier = new FloorTileRectifier(_map); actions.push(floorFixer); var lights:PlaceLights = new PlaceLights(_map); actions.push(lights); var sequence:AQueueAction = new AQueueAction(actions); sequence.getCompleted().add(onTilesRendered); sequence.invoke();
And it's pretty!var actions:Vector.= new Vector. (); var noise:NoiseAction = new NoiseAction(_map); noise.minX = 1; noise.minY = 1; noise.maxX = _map.width - 2; noise.maxY = _map.height - 2; noise.chanceToFill = 0.98; actions.push(noise); var erode:GlobAction = new GlobAction(_map); erode.filter = [true, false]; erode.fractionOfTotalSquaresToGlob = 1.5; actions.push(erode); var dilate:GlobAction = new GlobAction(_map); dilate.filter = [false, true]; dilate.fractionOfTotalSquaresToGlob = 1.0; actions.push(dilate); var spawnRect:Rectangle = new Rectangle(1, 1, 4, 3); var spawnArea:SetRectangleAction = new SetRectangleAction(_map); spawnArea.minX = spawnRect.x; spawnArea.maxX = spawnRect.right; spawnArea.minY = spawnRect.y; spawnArea.maxY = spawnRect.bottom; actions.push(spawnArea); var bigTree:TreesAction = new TreesAction(_map); bigTree.safeAreas.push(spawnRect); bigTree.minX = 5; bigTree.width = _map.width - 10; bigTree.minY = 5; bigTree.height = _map.height - 10; bigTree.minTreeSize = 6; bigTree.maxTreeSize = 9; bigTree.density = 1.0; bigTree.maxTreesOverride = 1; actions.push(bigTree); var trees:TreesAction = new TreesAction(_map); trees.minTreeSize = 1.5; trees.maxTreeSize = 3.0; trees.density = 0.55; trees.safeAreas.push(spawnRect); actions.push(trees); var trim:TrimCornerGaps = new TrimCornerGaps(_map); actions.push(trim); var floodFill:FloodFillMap= new FloodFillMap(_map, 3, 3); actions.push(floodFill); var floorFixer:FloorTileRectifier = new FloorTileRectifier(_map); actions.push(floorFixer); var lights:PlaceLights = new PlaceLights(_map); actions.push(lights); var sequence:AQueueAction = new AQueueAction(actions); sequence.getCompleted().add(onTilesRendered); sequence.invoke();
Well, the tree scenery needs some work. But as a map this will be fun to play on, and now we have infinite variety.
There are some holes to fill here. For one thing we should be using a repeatable pseudo-random number generator, so that we can iterate better, and so that we can regenerate the same map given a seed. That could be really valuable. For another thing we need to do some validation to make sure that the map we generate is actually playable.
But I think this is a good proof of concept and it's already fun to play with and on.









No comments:
Post a Comment