Monday, January 12, 2015

Hex Terrain Mapping Complete

Wetlands Added

The terrain mapping for my fractal world generation is now complete, with the addition of swamps and an occasional fungal forest.  I decided to take the simple approach to swamps, and set a terrain hex to swamp if its moisture level was close to the high end, and the ground was level.  Fungal forests can appear in these same conditions, but can quickly grow to cover over much of the surrounding terrain, so they add somewhat of a wildcard to the mix.

Sample World

Here's the randomly seeded world #1482326029 (yes, you can regenerate the same world by supplying the seed value) in snapshot.  I went with 40% land and a size of 768x300 hexes.  This world happened to have a good range of terrains, from ultra-lush jungles and swamps to arid deserts.  I'll highlight a couple area of note.


Fertile Delta

Here a river flows between two mountain ranges, creating a fertile area of lush forests and jungles amidst a generally arid desert environment.


Fungal Forest

There happened to be only one fungal forest generated on this world, in the red box below.  This bizarre terrain could form the basis of quests to retrieve rare spell components.


Campaign Start?

I've often used islands as a starting point for campaigns.  Their limited geographic area established handy constraints for low level parties.  Once the potential adventures on the island are resolved, its time to board a ship and head for new shores.  The generator produces worlds with many realistic islands and archipelagos to pick from.


What's Next

Next steps will be laying the groundwork for introducing cultures/races into the world, the birth of settlements, conflicts, expansion, etc.

Thursday, January 8, 2015

River Generation

Recap

With the terrain hexes of my fractal world generator mapped out, I have the basis of a campaign world in the form of a hex map.  The next important feature to add is rivers.

Rivers

Rivers should begin from the higher points on the map, and snake their way down until they hit a water hex.  I first randomly determine how many rivers to place on the map, and then build a list of candidate origin spaces which are the highest points in the elevation map.  I then take random candidates from the list, and ensure that they are not too close to the origins of previously formed rivers.

With the origin set, I look at the origin point's neighbor hexes, and move the river down into the one with the lowest elevation.  I repeat the process, winding the river down, until it's deposited into a water hex.

Moisture

For each of the hexes that contains a river, I bump up the moisture level.  The intention here is to potentially yield something like the Nile river, which cuts through a desert, but is flanked by lush vegetation.

Example


Here's a river originating in a colder region of the world, beginning in the mountain range to the west.  It snakes to the right, then up, and again to the right, to finally run off into the ocean.  Cutting through an area of cold desert, the moisture from the river causes evergreen forests and shrubland to grow along its banks.

Wednesday, January 7, 2015

Mapping Terrain Hexes

Recap

After completing the elevation map, temperature map, and moisture map, I'm ready to try and put these pieces together and determine terrain types for each hex on my dynamically generated fractal world.

Blur

Before tackling the terrain mapping, one aspect of the generated maps was bothering me.  They were too noisy.  Too many tiny island and lakes, more so than in natural world terrain.  I decided to apply two passes of a simple blur filter to the elevation map before the subsequent processing steps.  The results are more pleasing, but it's possible I might increase the number of blurs even more if the worlds still look too noisy.

Elevation Map with 2 Blur Passes
Terrain Mapping

I used the diagram below as a reference for mapping a point on the elevation map to a terrain.  First, I determine by the elevation if the hex is a flatland, hills, or mountain.  Then, I cross reference the temperature by the moisture to determine the appropriate terrain type.  For example, if it's a mountain hex, possible terrain types might be mountain, evergreen mountain, forested mountain, or jungle mountain.  I then made the tallest mountains on the maps into snow peaks, and threw in a minute chance of one or more volcanos popping up.


Terrain Mapping Results

Here's the example world above mapped to hexes.  The world is 768x300 hexes, or 230,400 total hexes.  I had to shrink the image quite a bit in order for blogger to accept it.  I like the shapes of the land masses, and the look of the mountain ranges.  If there's one thing I would tune, it would probably be to decrease the overall moisture level so more plains and shrub lands manifest.  But I think that the moisture control will be a tweakable dial in the final product, so you can create lush jungle worlds or barren desert worlds, as desired.


Since it's difficult to make out the individual hexes in this image, here's a section zoomed in.


What's Next?

I'm starting to consider how to populate the world with various fantasy races.  I'm leaning toward trying to model a simulated history.  Start by putting some primitive tribes on the map, let them advance and expand, and eventually come into contact and either ally or conflict, depending on their alignments.  As civilizations grow, settlements will spring into existence organically, and grow from villages to towns to cities, or might get razed by war and wind up as ruins.

But that's not immediately next in the development queue.  Next I'm going to integrate the other terrain types that haven't made an appearance yet, namely swamps and fungal forests.  Oh, and I almost forgot ... rivers.  And I might just start building those terrain hooks I talked about earlier, and throw some elemental portals into the mix to see how they mess up the climate and the resulting terrains.

Tuesday, January 6, 2015

Fast Moisture Simulation

Recap

In the previous post I described my attempt to model average precipitation (moisture) in my fractal world generator.  While the end result was acceptable, the amount of processing time needed to complete hundreds of cycles of simulated air circulation was too much.  I needed a faster approach.

Approximating

Rather than slavishly attempt to model every pixel of air movement, I decided to try a randomized approximation that would hopefully yield similar results.  My new moisture simulation performs 10 cycles of the following steps:

  1. Adds a small amount of moisture to each point on the map.
  2. Determine a random offset to the left/right and up/down.  Rather than 1 pixel shifts like in my previous model, the maximum offset is 20% of the map size, and the minimum 5%.
  3. Take an image of the elevation map, shift it by the offset amount, and use the elevation values to modify the moisture map.  Low elevations will add to the moisture map, and higher elevations will subtract from it.
Results

Approximated Moisture Map








Here are the results applied to the same fractal world as the previous example.  On the plus side, this method resulted in more amorphous moisture blobs, which I think will work better once this data is used to map to terrain hexes.  We still have low moisture areas (blue) which will translate to deserts, but they aren't as precisely defined as the previous method.  Bottom line, I think this approach will yield a result just as usable as the more intensive method, at about one hundredth of the processing time required, so it's a win!

Monday, January 5, 2015

Moisture Simulation

Recap

I'm developing a random RPG campaign map generator, and have the following pieces in place:


Precipitation

The next piece of the puzzle is generating a moisture map that represents the average precipitation at each point on the world.  A combination of the temperature, moisture, and elevation will ultimately determine which hex terrain is chosen for a particular point.

Algorithm

My first pass at modeling precipitation can be summed up as:
  1. Create several randomized wind bands.  Winds will blow left to right across the map, but these randomized zones will provide some cross-currents.
  2. Complete a number of cycles of simulated air circulation.  The number of cycles is set to the width of the map.  With the maps I am currently working with, this means 768 cycles of simulated air circulation.  For each cycle:
    1. For every water point on the map, add a small amount of moisture to that point.
    2. Use the wind bands to "blow" the air map one space.
    3. Subtract a small amount of moisture from each point, based on the elevation at that point.  This step is intended to simulate the deserts that can form next to mountain ranges.
Results

The example below shows a simulated moisture map after 768 cycles of simulated air circulation.  I'm generally pleased with the result.  The mountains in the upper left continent are producing a large desert region, there are numerous areas of moderate moisture which will map to plains, and much of the map has high moisture, which will lead to forests and jungles, depending on the temperate in the area.

The only problem with the approach is the processing time involved.  It takes about 15 seconds of processing to complete the 768 cycles of simulated air circulation.  I think I can create a simpler approach that will be orders of magnitude faster, and still produce acceptable results.

Elevation Map
Moisture Map after 768 cycles

Sunday, January 4, 2015

Temperature Zones

Recap

Work on my fractal world and dynamic campaign map generator continues.  With an elevation map in place, and basic hex mapping accomplished, this next step will move us toward ultimately more realistic terrain.

Research

My crash course in biome generation led me to Community and Ecosystem Dynamics, which I think has most of what I need to get an adequate model developed.  After digesting most of this, I concluded that the first step would be dividing the world into temperature zones.

Algorithm

I implemented a simple algorithm to produce a temperature map of the world, based on a minimum and a maximum temperature as parameters.  The default minimum temperature is -15˚ C., and the default maximum is 30˚ C.  You'll be able to supply different parameters to generate colder or warmer worlds as desired.

The exact temperature at each point on the map is calculated by the longitude (assuming an equator at the center), and the elevation, with a slight randomization applied.

Example

In the example below, note how areas of higher elevation have an overall cooling effect on the region.

Fractal World Elevation Map
Corresponding Temperature Map
Future Hooks

As the project progresses, I will need to add hooks into the fractal world generator to account for localized anomalies in temperature.  For example, in my home D&D campaign, there are numerous portals into various elemental planes that make their surrounding regions much colder or hotter.  Also, certain large monsters could have an affect on the surrounding climate.  It will be exciting, for example, to produce a large localized region of cold from an elemental portal and see the resulting terrain get generated as tundra and ice fields.

Saturday, January 3, 2015

Fractal World Mapped to Hexes

Mapping to Hexes

In day two of my dynamic campaign world generator development I built a rough translation of the elevation maps from yesterday into a hex grid.  I did a very basic mapping of elevation values to three "terrains", green for plains, yellow for hills, brown for mountains.  This mapping is purely temporary.  As the project advances I plan to build a climate and biome generator which will ultimately produce more varied and interesting terrain.

Different Worlds

The fractal world generator can produce worlds in a variety of styles.  For the two examples below, I decided to crank up the generator to 768x200 pixels.  Since each pixel of the fractal world will map to a hex, this gives us a campaign world of 153,600 hexes.  I plan to use a scale of 5 miles per hex myself, so this will give me a campaign map of 3,840 x 1,000 miles.  Of course, the size parameters will be adjustable in the final product.

The first example shows a world with three distinct continents, separated by oceans, with a few smaller land masses.









In contrast, this world is more amorphous, with numerous chains of islands connecting the larger continents.









Let's take a look at the amorphous world with the basic hex mapping applied.  Quite a bit of terrain there to populate and explore!  The next step will be working on the climate and biome generator to start producing some forests, swamps, deserts, and more.


Friday, January 2, 2015

Fractal Worlds

A World at the Press of a Button

The idea of generating a complete campaign world at the press of a virtual button is very intriguing to me.  My appreciation of randomness in RPGs began when I was surprised by how playable the random dungeons generated in the Warhammer Quest tabletop game were.  With a well-seeded set of random tables, an interesting story will unfold.

The Concept

There is already some great groundwork for dynamic campaign world generation out there, and new projects like Worldspinner look very promising.  But I'm going to take on the challenge of creating a campaign world generator as well.  My twist: the project will be powered by my DMMuse.com database of random tables and generators.

DMMuse is a curated, open repository of RPG generators.  The idea is for community members to help populate the tables, resulting in an ever-growing store of value.  With the DMMuse framework well established, I have an engine that can generate the random settlements, adventure locations, and lairs that will eventually populate the procedurally generated campaign world.

First Step - Elevation Map

The first step in creating the world is getting a basic world map.  I implemented a fractal world builder that spits out an elevation map of a randomly generated world.  An example is shown above.  This particular map is 150x100 pixels in size.  When converted to a hex map, that gives us a campaign map of 15,000 hexes.

Taking this elevation map and converting it into a basic hex map will be the next step in the process.