Package squidpony.squidgrid.mapping
Class DungeonGenerator
java.lang.Object
squidpony.squidgrid.mapping.DungeonGenerator
- All Implemented Interfaces:
IDungeonGenerator
public class DungeonGenerator extends Object implements IDungeonGenerator
The primary way to create a more-complete dungeon, layering different effects and modifications on top of
a DungeonBoneGen's dungeon or another dungeon without such effects. Also ensures only connected regions of the map
are used by filling unreachable areas with walls, and can find far-apart staircase positions if generate() is used or
can keep existing staircases in a map if generateRespectingStairs() is used.
The main technique for using this is simple: Construct a DungeonGenerator, usually with the desired width and height, then call any feature adding methods that you want in the dungeon, like addWater(), addTraps, addGrass(), or addDoors(). Some of these take different parameters, like addDoors() which need to know if it should check openings that are two cells wide to add a door and a wall to, or whether it should only add doors to single-cell openings. Then call generate() to get a char[][] with the desired dungeon map, using a fixed repertoire of chars to represent the different features. After calling generate(), you can safely get the values from the stairsUp and stairsDown fields, which are Coords that should be a long distance from each other but connected in the dungeon. You may want to change those to staircase characters, but there's no requirement to do anything with them. It's recommended that you keep the resulting char[][] maps in some collection that can be saved, since DungeonGenerator only stores a temporary copy of the most recently-generated map. The DungeonUtility field of this class, utility, is a convenient way of accessing the non-static methods in that class, such as randomFloor(), without needing to create another DungeonUtility (this class creates one, so you don't have to).
Previews for the kinds of dungeon this generates, given a certain argument to generate():
As of March 6, 2016, the algorithm this uses to place water and grass was swapped for a more precise version. You no longer need to give this 150% in addWater or addGrass to effectively produce 100% water or grass, and this should be no more than 1.1% different from the percentage you request for any effects. If you need to reproduce dungeons with the same seed and get the same (imprecise) results as before this change, it's probably not possible unless you save the previously-generated char[][] dungeons, since several other things may have changed as well.
The main technique for using this is simple: Construct a DungeonGenerator, usually with the desired width and height, then call any feature adding methods that you want in the dungeon, like addWater(), addTraps, addGrass(), or addDoors(). Some of these take different parameters, like addDoors() which need to know if it should check openings that are two cells wide to add a door and a wall to, or whether it should only add doors to single-cell openings. Then call generate() to get a char[][] with the desired dungeon map, using a fixed repertoire of chars to represent the different features. After calling generate(), you can safely get the values from the stairsUp and stairsDown fields, which are Coords that should be a long distance from each other but connected in the dungeon. You may want to change those to staircase characters, but there's no requirement to do anything with them. It's recommended that you keep the resulting char[][] maps in some collection that can be saved, since DungeonGenerator only stores a temporary copy of the most recently-generated map. The DungeonUtility field of this class, utility, is a convenient way of accessing the non-static methods in that class, such as randomFloor(), without needing to create another DungeonUtility (this class creates one, so you don't have to).
Previews for the kinds of dungeon this generates, given a certain argument to generate():
- Using TilesetType.DEFAULT_DUNGEON (text, click "Raw", may need to zoom out): https://gist.github.com/tommyettinger/a3bd413b903f2e103541
- Using TilesetType.DEFAULT_DUNGEON (graphical, scroll down and to the right): http://tommyettinger.github.io/home/PixVoxel/dungeon/dungeon.html
- Using SerpentMapGenerator.generate() (text, click "Raw", may need to zoom out): https://gist.github.com/tommyettinger/93b47048fc8a209a9712
As of March 6, 2016, the algorithm this uses to place water and grass was swapped for a more precise version. You no longer need to give this 150% in addWater or addGrass to effectively produce 100% water or grass, and this should be no more than 1.1% different from the percentage you request for any effects. If you need to reproduce dungeons with the same seed and get the same (imprecise) results as before this change, it's probably not possible unless you save the previously-generated char[][] dungeons, since several other things may have changed as well.
- Author:
- Eben Howard - http://squidpony.com - howard@squidpony.com, Tommy Ettinger - https://github.com/tommyettinger
- See Also:
this class exposes a DungeonUtility member; DungeonUtility also has many useful static methods
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
DungeonGenerator.FillEffect
The effects that can be applied to this dungeon. -
Field Summary
Fields Modifier and Type Field Description protected char[][]
dungeon
EnumMap<DungeonGenerator.FillEffect,Integer>
fx
The effects that will be applied when generate is called.protected DungeonBoneGen
gen
protected int
height
protected long
rebuildSeed
IStatefulRNG
rng
protected boolean
seedFixed
Coord
stairsDown
Coord
stairsUp
DungeonUtility
utility
protected int
width
-
Constructor Summary
Constructors Constructor Description DungeonGenerator()
Make a DungeonGenerator with a GWTRNG using a random seed, height 40, and width 40.DungeonGenerator(int width, int height)
Make a DungeonGenerator with the given height and width; a GWTRNG will be used for generating a dungeon and adding features using a random seed.DungeonGenerator(int width, int height, IRNG rng)
Make a DungeonGenerator with the given height, width, and RNG.DungeonGenerator(DungeonGenerator copying)
Copies all fields from copying and makes a new DungeonGenerator. -
Method Summary
Modifier and Type Method Description DungeonGenerator
addBoulders(int percentage)
Turns the given percentage of floor cells not already adjacent to walls into wall cells, represented by '#'.DungeonGenerator
addDoors(int percentage, boolean doubleDoors)
Turns the given percentage of viable doorways into doors, represented by '+' for doors that allow travel along the x-axis and '/' for doors that allow travel along the y-axis.DungeonGenerator
addGrass(int percentage)
Turns the majority of the given percentage of floor cells into grass cells, represented by '"'.DungeonGenerator
addTraps(int percentage)
Turns the given percentage of open area floor cells into trap cells, represented by '^'.DungeonGenerator
addWater(int percentage)
Turns the majority of the given percentage of floor cells into water cells, represented by '~'.DungeonGenerator
addWater(int percentage, int islandSpacing)
Turns the majority of the given percentage of floor cells into water cells, represented by '~'.DungeonGenerator
clearEffects()
Removes any door, water, or trap insertion effects that this DungeonGenerator would put in future dungeons.char[][]
generate()
Generate a char[][] dungeon using TilesetType.DEFAULT_DUNGEON; this produces a dungeon appropriate for a level of ruins or a partially constructed dungeon.char[][]
generate(char[][] baseDungeon)
Generate a char[][] dungeon with extra features given a baseDungeon that has already been generated.char[][]
generate(TilesetType kind)
Generate a char[][] dungeon given a TilesetType; the comments in that class provide some opinions on what each TilesetType value could be used for in a game.char[][]
generateRespectingStairs(char[][] baseDungeon)
Generate a char[][] dungeon with extra features given a baseDungeon that has already been generated, and that already has staircases represented by greater than and less than signs.char[][]
getBareDungeon()
Get the most recently generated char[][] dungeon out of this class without any chars other than '#' or '.', for walls and floors respectively.char[][]
getDungeon()
Get the most recently generated char[][] dungeon out of this class.int
getHeight()
Height of the dungeon in cells.long
getRebuildSeed()
Gets the seed that can be used to rebuild an identical dungeon to the latest one generated (or the seed that will be used to generate the first dungeon if none has been made yet).int
getWidth()
Width of the dungeon in cells.protected OrderedSet<Coord>
removeAdjacent(OrderedSet<Coord> coll, Coord pt)
protected OrderedSet<Coord>
removeAdjacent(OrderedSet<Coord> coll, Coord pt1, Coord pt2)
void
setDungeon(char[][] dungeon)
Change the underlying char[][]; only affects the toString method, and of course getDungeon.String
toString()
Provides a string representation of the latest generated dungeon.protected OrderedSet<Coord>
viableDoorways(boolean doubleDoors, char[][] map)
-
Field Details
-
Constructor Details
-
DungeonGenerator
public DungeonGenerator()Make a DungeonGenerator with a GWTRNG using a random seed, height 40, and width 40. -
DungeonGenerator
Make a DungeonGenerator with the given height and width; a GWTRNG will be used for generating a dungeon and adding features using a random seed. If width or height is greater than 256, then this will expand the Coord pool from its 256x256 default so it stores a reference to each Coord that might be used in the creation of the dungeon (if width and height are 300 and 300, the Coord pool will be 300x300; if width and height are 500 and 100, the Coord pool will be 500x256 because it won't shrink below the default size of 256x256).- Parameters:
width
- The width of the dungeon in cellsheight
- The height of the dungeon in cells
-
DungeonGenerator
Make a DungeonGenerator with the given height, width, and RNG. Use this if you want to seed the RNG. If width or height is greater than 256, then this will expand the Coord pool from its 256x256 default so it stores a reference to each Coord that might be used in the creation of the dungeon (if width and height are 300 and 300, the Coord pool will be 300x300; if width and height are 500 and 100, the Coord pool will be 500x256 because it won't shrink below the default size of 256x256).- Parameters:
width
- The width of the dungeon in cellsheight
- The height of the dungeon in cellsrng
- The RNG to use for all purposes in this class; if it is a StatefulRNG, then it will be used as-is, but if it is not a StatefulRNG, a new StatefulRNG will be used, randomly seeded by this parameter
-
DungeonGenerator
Copies all fields from copying and makes a new DungeonGenerator.- Parameters:
copying
- the DungeonGenerator to copy
-
-
Method Details
-
getDungeon
Get the most recently generated char[][] dungeon out of this class. The dungeon may be null if generate() or setDungeon() have not been called.- Specified by:
getDungeon
in interfaceIDungeonGenerator
- Returns:
- a char[][] dungeon, or null.
-
getBareDungeon
Get the most recently generated char[][] dungeon out of this class without any chars other than '#' or '.', for walls and floors respectively. The dungeon may be null if generate() or setDungeon() have not been called.- Returns:
- a char[][] dungeon with only '#' for walls and '.' for floors, or null.
-
setDungeon
Change the underlying char[][]; only affects the toString method, and of course getDungeon.- Parameters:
dungeon
- a char[][], probably produced by an earlier call to this class and then modified.
-
getHeight
Height of the dungeon in cells.- Returns:
- Height of the dungeon in cells.
-
getWidth
Width of the dungeon in cells.- Returns:
- Width of the dungeon in cells.
-
addWater
Turns the majority of the given percentage of floor cells into water cells, represented by '~'. Water will be clustered into a random number of pools, with more appearing if needed to fill the percentage. Each pool will have randomized volume that should fill or get very close to filling the requested percentage, unless the pools encounter too much tight space. If this DungeonGenerator previously had addWater called, the latest call will take precedence. No islands will be placed with this variant, but the edge of the water will be shallow, represented by ','.- Parameters:
percentage
- the percentage of floor cells to fill with water- Returns:
- this DungeonGenerator; can be chained
-
addWater
Turns the majority of the given percentage of floor cells into water cells, represented by '~'. Water will be clustered into a random number of pools, with more appearing if needed to fill the percentage. Each pool will have randomized volume that should fill or get very close to filling the requested percentage, unless the pools encounter too much tight space. If this DungeonGenerator previously had addWater called, the latest call will take precedence. If islandSpacing is greater than 1, then this will place islands of floor, '.', surrounded by shallow water, ',', at about the specified distance with Euclidean measurement.- Parameters:
percentage
- the percentage of floor cells to fill with waterislandSpacing
- if greater than 1, islands will be placed randomly this many cells apart.- Returns:
- this DungeonGenerator; can be chained
-
addGrass
Turns the majority of the given percentage of floor cells into grass cells, represented by '"'. Grass will be clustered into a random number of patches, with more appearing if needed to fill the percentage. Each area will have randomized volume that should fill or get very close to filling the requested percentage, unless the patches encounter too much tight space. If this DungeonGenerator previously had addGrass called, the latest call will take precedence.- Parameters:
percentage
- the percentage of floor cells to fill with grass- Returns:
- this DungeonGenerator; can be chained
-
addBoulders
Turns the given percentage of floor cells not already adjacent to walls into wall cells, represented by '#'. If this DungeonGenerator previously had addBoulders called, the latest call will take precedence.- Parameters:
percentage
- the percentage of floor cells not adjacent to walls to fill with boulders.- Returns:
- this DungeonGenerator; can be chained
-
addDoors
Turns the given percentage of viable doorways into doors, represented by '+' for doors that allow travel along the x-axis and '/' for doors that allow travel along the y-axis. If doubleDoors is true, 2-cell-wide openings will be considered viable doorways and will fill one cell with a wall, the other a door. If this DungeonGenerator previously had addDoors called, the latest call will take precedence.- Parameters:
percentage
- the percentage of valid openings to corridors to fill with doors; should be between 10 and 20 if you want doors to appear more than a few times, but not fill every possible opening.doubleDoors
- true if you want two-cell-wide openings to receive a door and a wall; false if only one-cell-wide openings should receive doors. Usually, this should be true.- Returns:
- this DungeonGenerator; can be chained
-
addTraps
Turns the given percentage of open area floor cells into trap cells, represented by '^'. Corridors that have no possible way to move around a trap will not receive traps, ever. If this DungeonGenerator previously had addTraps called, the latest call will take precedence.- Parameters:
percentage
- the percentage of valid cells to fill with traps; should be no higher than 5 unless the dungeon floor is meant to be a kill screen or minefield.- Returns:
- this DungeonGenerator; can be chained
-
clearEffects
Removes any door, water, or trap insertion effects that this DungeonGenerator would put in future dungeons.- Returns:
- this DungeonGenerator, with all effects removed. Can be chained.
-
removeAdjacent
-
removeAdjacent
-
viableDoorways
-
generate
Generate a char[][] dungeon using TilesetType.DEFAULT_DUNGEON; this produces a dungeon appropriate for a level of ruins or a partially constructed dungeon. This uses '#' for walls, '.' for floors, '~' for deep water, ',' for shallow water, '^' for traps, '+' for doors that provide horizontal passage, and '/' for doors that provide vertical passage. Use the addDoors, addWater, addGrass, and addTraps methods of this class to request these in the generated map. Also sets the fields stairsUp and stairsDown to two randomly chosen, distant, connected, walkable cells.- Specified by:
generate
in interfaceIDungeonGenerator
- Returns:
- a char[][] dungeon
-
generate
Generate a char[][] dungeon given a TilesetType; the comments in that class provide some opinions on what each TilesetType value could be used for in a game. This uses '#' for walls, '.' for floors, '~' for deep water, ',' for shallow water, '^' for traps, '+' for doors that provide horizontal passage, and '/' for doors that provide vertical passage. Use the addDoors, addWater, addGrass, and addTraps methods of this class to request these in the generated map. Also sets the fields stairsUp and stairsDown to two randomly chosen, distant, connected, walkable cells.- Parameters:
kind
- a TilesetType enum value, such as TilesetType.DEFAULT_DUNGEON- Returns:
- a char[][] dungeon
- See Also:
TilesetType
-
generate
Generate a char[][] dungeon with extra features given a baseDungeon that has already been generated. Typically, you want to call generate with a TilesetType or no argument for the easiest generation; this method is meant for adding features like water and doors to existing simple maps. This uses '#' for walls, '.' for floors, '~' for deep water, ',' for shallow water, '^' for traps, '+' for doors that provide horizontal passage, and '/' for doors that provide vertical passage. Use the addDoors, addWater, addGrass, and addTraps methods of this class to request these in the generated map. Also sets the fields stairsUp and stairsDown to two randomly chosen, distant, connected, walkable cells.
Special behavior here: If tab characters are present in the 2D char array, they will be replaced with '.' in the final dungeon, but will also be tried first as valid staircase locations (with a high distance possible to travel away from the starting staircase). If no tab characters are present this will search for '.' floors to place stairs on, as normal. This tab-first behavior is useful in conjunction with some methods that establish a good path in an existing dungeon; an example isDungeonUtility.ensurePath(dungeon, rng, '\t', '#');
then passing dungeon (which that code modifies) in as baseDungeon to this method.- Parameters:
baseDungeon
- a pre-made dungeon consisting of '#' for walls and '.' for floors; may be modified in-place- Returns:
- a char[][] dungeon
-
generateRespectingStairs
Generate a char[][] dungeon with extra features given a baseDungeon that has already been generated, and that already has staircases represented by greater than and less than signs. Typically, you want to call generate with a TilesetType or no argument for the easiest generation; this method is meant for adding features like water and doors to existing simple maps. This uses '#' for walls, '.' for floors, '~' for deep water, ',' for shallow water, '^' for traps, '+' for doors that provide horizontal passage, and '/' for doors that provide vertical passage. Use the addDoors, addWater, addGrass, and addTraps methods of this class to request these in the generated map. Also sets the fields stairsUp and stairsDown to null, and expects stairs to be already handled.- Parameters:
baseDungeon
- a pre-made dungeon consisting of '#' for walls and '.' for floors, with stairs already in; may be modified in-place- Returns:
- a char[][] dungeon
-
getRebuildSeed
Gets the seed that can be used to rebuild an identical dungeon to the latest one generated (or the seed that will be used to generate the first dungeon if none has been made yet). You can pass the long this returns to the setState() method on this class' rng field, which assuming all other calls to generate a dungeon are identical, will ensure generate() or generateRespectingStairs() will produce the same dungeon output as the dungeon originally generated with the seed this returned.
You can also call getState() on the rng field yourself immediately before generating a dungeon, but this method handles some complexities of when the state is actually used to generate a dungeon; since StatefulRNG objects can be shared between different classes that use random numbers, the state could change between when you call getState() and when this class generates a dungeon. Using getRebuildSeed() eliminates that confusion.- Returns:
- a seed as a long that can be passed to setState() on this class' rng field to recreate a dungeon
-
toString
Provides a string representation of the latest generated dungeon.
-