World Generation Teaser
Happy 2013 everyone! Rather than risking going three months without an update, I figured I’d post some teaser screenshots of the world generation progress on my latest project:
Elevation and water line
Here’s the first pass, mostly focused on getting the land formation looking good with Perlin noise, and sampling the water to ensure a landmass percentage. I’ve also ensured the edges of the map taper off by multiplying the elevation values times a box gradient.
Perlin distortion
A plain Perlin noise elevation is pretty tame, so I figured I’d throw a twist in it this time around and applied a Perlin noise distortion. My distortion implementation involves generating two additional 2D Perlin noise maps, using one to determine the x-offset and another the y. I then sample the original map with these offsets multiplied by a maximum amplitude. It’s worth noting that Ken Perlin’s original C implementation outputs values between -1 and 1, so sampling offsets for a distortion is straightforward. It’s also worth noting that because Objective-C is a superset of C, said original implementation can be used straight out, no porting necessary (although you’ll need to do some work to output the fBm you’re likely expecting).
Floodfilling to identify landmasses
Landmasses have been floodfilled to identify continents and islands (differences not pictured). I’ve picked a somewhat arbitrary minimum area to qualify as a continent (I believe around 4000 tiles), which will determine starting areas for players.
Wind map
Inspired by the [now defunct?] Dungeon League article on Wind Direction, I’ve generated an interpolated wind map, then distorted the result with a Perlin noise distortion. Pictured are the degrees of the wind mapped to 0-255.
Wind vectors over land
Arbitrary wind directions are a good starting point, but the purpose of the wind is to determine humidity distribution by simulating how far moisture would have to travel from water to a given tile, with the added obstructions of mountains that are higher than cloud elevation. To this end, the wind direction on one tile must point towards another tile, so it is necessary to clamp the wind directions to the four cardinal and diagonal directions, resulting in 45° zones. The first pass at clamping had hard boundaries between the zones, which meant the resulting rain shadow had too many straight edges, which then resulted in rather unorganically-bound biomes. To solve this, I set up a random dithering rather than clamping. Pictured are wind directions N, NE, E, SE, S, etc. with a corresponding solid color assigned.
Rain shadow
Also taking a cue from the Dungeon League article on this topic, I then step backwards through the wind vectors, starting at each land tile, and count how many tiles it takes to get to water or to another tile whose humidity has already been set. I set an upper clamp for how long this can go on, in the odd but remotely possible case that you catch a wind loop that never touches water. This max value is also assigned to areas above cloud elevation, which results in mountains creating a rain shadow.
Next steps
I’ve stopped just short of identifying biomes, which is the next step, precluded by a quick temperature gradient generation.
For this particular game, biomes add flavor rather than being a key part of the gameplay, so I’ve shifted gears to building a simple tiling system to represent the terrain. After all, each world tile will be larger than two pixels in the actual game!
I really like the noise distortion – I’ll have to remember that. One thing I don’t like about using natural processes to make the map is that you can end up with very boring stuff. Like a huge continent that’s almost all the same forest. Just something I’ve noticed.
It is possible to end up with one huge continent, but mixing up humidity and temperature (the latter which not illustrated in this post), ensures that even if you have a fairly boring topography you’ll end up with an interesting mixture of biomes. This is certainly much more of a problem if you only use elevation information to determine the terrain type.
That map looks really good. I am currently trying to create something similar in java, but my map looks like, well normal noise.
I know that this is quite old, but could you maybe explain a little bit further how exactly you created this? (e.g. octaves, how many different noises were combined,…)
It would really help me a lot.
Jacky
Jacky, have a look at the World Generation Breakdown article for a more thorough explanation of how I achieved the base map effect.
What exactly are you having trouble with? If it’s octaves, specifically: each noise octave represents a finer resolution of noise (half amplitude and double frequency) sampling that is then added to the previous sample. The basic definition of Perlin noise only operates upon one octave. Flash’s implementation is closer to what is commonly referred as Fractal Noise or Fractal Brownian Noise as described in this article: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
If you see, for example, a noise with 5 octaves that starts at 128 amplitude and 4 frequency, it really is equals to:
Octave 1: Amplitude 128, Frequency 4
+
Octave 2: Amplitude 64, Frequency 8
+
Octave 3: Amplitude 32, Frequency 16
+
Octave 4: Amplitude 16, Frequency 32
+
Octave 5: Amplitude 8, Frequency 64
You can notice that as the amplitude gets smaller it starts to be too fine to be even noticeable, which is why the difference between a 1 and 2 octave noise is clearly visible, but not so much so between an octave 8 and 9 noise.
Hope that helps. Let me know if you need any additional clarifications!
Thanks for the amazing read!
Might be a bit of a stupid question, but how do you create a square gradient? Searches on google all ended up with tutorials for Photoshop or differential operators (Thanks to past searches, I assume).
Hey!
Great article. I was trying to create a wind map as stated in the blog, but for some reason the wind maps I get aren’t very distorted:
http://imgur.com/VEBxUM1 (Colors are the HSV with the wind angle)
I tried increasing the amplitude of the offset and adding more iterations of distortion, but nothing seems to help…
Could you explain the distortion more into detail?
Thanks!
Fred, at a glance I suspect you’re only using one noise to offset both the x and the y (the slanty nature of the distortion is what’s tipping me off). Try two different noise maps, one affects the x distortion and one the y.
Ofek, for a square gradient, measure the distance to the nearest edge on X and Y and take the smallest value, so you end up with something like this:
A quick method of achieving this is to take the minimum value of x, y, width-1-x, and height-1-y.
You can then assign a value to these distances depending on your purposes. For example, if you want to create a box gradient that keeps the center fully white and starts to fade 3 tiles from the edge, you may say that everything >= 3 is full white, and then use simple proportion to interpolate to the edge. If your “white” corresponding to a distance of 3 is 255, then a distance of 2 would ramp down to 2/3 * 255 = 170, 1 to 1/3 * 255 = 85, and 0 to 0.
Hope that helps!
Thanks for the answer. I’m using 2 different perlin noise maps, 1 for Y and 1 for X.
Did you use extremely high frequency or amplitude to get better distortion? I can’t seem to hit the spot for it, it always stays pretty dull…
Are you still interested in world generation? We are building a small community around WorldEngine, building an open-source, cross-platform, interoperable world generator https://github.com/Mindwerks/worldengine.
It would be great to have comments and contributions!