FlexGen Cookbook

Overview

This is the FlexGen Cookbook. It will walk you through the steps needed to generate a map with the FlexGen library, using samples from the example application. The example application is included in the "example" directory in the FlexGen release.

There are several elements you must define when generating a map: map tiles, map tile edges, and map units. Map tiles are the basic building block of maps. You must define several map tile types that will be used to create your map. Map tile edges define which map tile types may be placed adjacent to another map tile type within the map. Map units are the smallest element present in a map and are used to construct map tiles.

FlexGen generates maps by randomly selecting a map tile type and then placing a map tile of the specified type in a randomly selected empty location with a random orientation. A particular location and orientation can only be considered where the four edges of the selected map tile type in the particular orientation match the corresponding edges of map tiles adjacent to the particular location. This process is repeated until there are no empty locations remaining in the map.

Map Units

Map units represent the fundamental elements that will compose your map. In the example application, a map is generated that has rivers cutting through grassland. The map units in the example application are grass and river. Each map unit in your map must have a unique name, as the name is used to differentiate one map unit from another. Map units can be constructed with the following example:

    MapUnit grass = new MapUnit( "Grass" );
    MapUnit river = new MapUnit( "River" );
                

Map Tile Edges

Map tile edges determine how map tiles may be placed adjacent to each other. Each map tile type will have a map tile edge specified for each of its four edges. When determining whether or not a map tile can be placed adjacent to another map tile, the edges connecting both of the map tiles must match. For example, if a map tile is being placed on top of another map tile, the bottom edge of the new map tile must match the top edge of the existing map tile. If a map tile is being placed adjacent to more than one map tile, this check is performed for all adjacent tiles. The map tile edges in the example application define an edge that is made up entirely of grass and an edge with a river flowing through the middle. Each map tile edge in your map must have a unique name, as the name is used to differentiate one map tile edge from another. Map tile edges can be constructed with the following example:

    MapTileEdge grassEdge = new MapTileEdge( "Grass Edge" );
    MapTileEdge riverEdge = new MapTileEdge( "River Edge" );
                

Map Tiles

A map tile type is comprised of a two-dimensional grid of map units that define the map tile type. Map tile types also have a unique name (to identify them), a weight (to make some map tile types more likely to be selected than others), an array of map tile edges defining the four edges of the map tile type, and an array of map tile orientations defining the distinct orientations available for the map tile type. While you can use any size for the two-dimensional grid of map units, the grid must be the same size vertically as it is horizontally. Also, every map tile type must have the same size grid. The map tile edges are specified in the following order: top, right, bottom, left.

The example application defines six different tile types. They represent various combinations of the grass and river map units that can be used to generate a map that has rivers cutting through grassland. The following gives a graphical representation of these six map tile types:

All Grass : All Grass
Straight River : Straight River
Corner River : Corner River
Three Way River : Three Way River
Four Way River : Four Way River
Dead End River : Dead End River

The following example demonstrates how to construct the straight river map tile type. Note that the top edge of the map tile type is river, the right edge is grass, the bottom edge is river, and the left edge is grass. Also note that due to the symmetry of the grid of map units, the map tile type has only two distinct orientations.

    MapTileType straightRiver = new MapTileType(
            "Straight River", 1000,
            new MapUnit[][]
            {
                { grass, river, grass },
                { grass, river, grass },
                { grass, river, grass }
            },
            new MapTileEdge[]
            {
                riverEdge,
                grassEdge,
                riverEdge,
                grassEdge
            },
            new MapTileOrientation[]
            {
                MapTileOrientation.UPRIGHT,
                MapTileOrientation.CLOCKWISE
            } );
                

The following example demonstrates how to construct the corner river map tile type. Note that the top edge of the map tile type is river, the right edge is river, the bottom edge is grass, and the left edge is grass. Also note that due to the lack of symmetry of the grid of map units, the map tile type has all four orientations. Finally, note that the weight of the corner river map tile type is 500 while the weight of the straight river map tile type is 1000. That means that the corner river map tile type is half as likely to be selected as the straight river map tile type.

    cornerRiver = new MapTileType(
            "Corner River", 500,
            new MapUnit[][]
            {
                { grass, river, grass },
                { grass, river, river },
                { grass, grass, grass }
            },
            new MapTileEdge[]
            {
                riverEdge,
                riverEdge,
                grassEdge,
                grassEdge
            },
            new MapTileOrientation[]
            {
                MapTileOrientation.UPRIGHT,
                MapTileOrientation.CLOCKWISE,
                MapTileOrientation.FLIPPED,
                MapTileOrientation.COUNTER_CLOCKWISE
            } );
                

Generating the Map

Now that all of the elements have been defined, it is time to construct the map generator and generate the map. First, you need a random number generator. You can either use the random number generator included with FlexGen, org.flexgen.util.ImprovedRandom, or use your own. If you use your own random number generator, it must be a sublcass of org.flexgen.util.ImprovedRandom, as that is what the map generator expects. The random number generator can be constructed with the following example:

    ImprovedRandom improvedRandom = new ImprovedRandom();
                

Next, you need to combine all of your defined map tile types into an array that you will pass to the map generator constructor. The six map tile types from the example application can be combined into an array with the following example:

    MapTileType[] mapTileTypes = new MapTileType[]
    {
        allGrass,
        straightRiver,
        cornerRiver,
        threeWayRiver,
        fourWayRiver,
        deadEndRiver
    };
                

Now you need to construct the map generator. The constructor for the map generator takes the random number generator, the array of map tile types, and the minimum and maximum X and Y coordinates for the map. The map generator can be constructed with the following example:

    MapGenerator mapGenerator = new MapGenerator(
            improvedRandom, mapTileTypes, -10, -10, 10, 10 );
                

The final step before generating the map is that you need to add whatever initial map tiles tiles you want to the map. You must add at least one map tile before generating the map. A map tile can be added to the map with the following example:

    mapGenerator.addMapTile(
            new MapTileLocation( 0, 0 ),
            new MapTile( allGrass, MapTileOrientation.UPRIGHT ));
                

Finally, you can generate the map. A map can be generated with the following example:

    mapGenerator.generate();
                

Getting Stuck

Version 1.0.0 of FlexGen has a known issue where the map generator can get "stuck" when generating the map. What this means is that that the map generator can get into a situation where it is impossible to place a map tile in a certain location in the map because no map tile type in any orientation can fit in that location. FlexGen has no logic to deal with this situation, and when it occurs an exception is thrown. To ensure this does not happen, you must define map tile types such that a map tile type exists for every possible combination of map tile edges that may occur in the map. Newer versions of FlexGen will contain logic to solve this problem without requiring you to define map tile types for every combination of map tile edges.