Since I’m making a light-weight strategy game with a screen size map, I implemented some basic procedural generation techniques to create the random map. I now have fairly nice islands being created randomly; here are three examples:
I probably need to polish it more for the final game (for starters, the beaches imply a scale around an island nation, but I may want more like a continent) but for now I’ll probably leave it like this and move on to other parts of the game. I’m aiming to have a prototype in players’ hands soon so that I can start gathering feedback, and I don’t really need anything more than the island outline for that initial prototype. Plus the publisher of my book just contacted me about possibly doing a 2nd edition, so I may be busy with that soon.
At any rate, here’s how it’s done:
The first resource I saw when I realized I would need a procedurally generated island was this article. The island generated from that method looks really nice, so I was planning to replicate that method in my own project. However, in a different article that same author advises trying a simpler approach first, so I decided to implement terrain generation with noise functions in the prototype, and then switch to voronoi cells when polishing the final game. Well, the results from using noise functions have been better than I expected, so I might not switch to voronoi cells after all. I do still want to experiment with that method eventually, but I might just wait until my next game instead of doing it in this project.
Anyway, the island shape results from three different algorithms smooshed together. First is a low-frequency perlin noise to get the large scale features, then high-frequency simplex noise is added in to perturb the large features with interesting terrain details, and finally I multiply that with an elliptical gradient so that the island will be surrounded by water (as opposed to terrain right up to the edge of the image).
Literally the first thing I implemented was displaying perlin noise. Nothing fancy, just the obvious place to start. The perlin function was giving a value from 0 to 1 for every pixel, so I rendered colors with a threshold value: anything below the threshold was blue, anything above was green. At this point I had:
Now I needed the data to fade out (ie. go to 0) towards the edges. I saw some discussions online suggesting to reduce the value based on the pixel’s distance from the center of the image (essentially, multiply the perlin noise by a circular gradient) and I realized I could do that with an ellipse instead (ie. instead of looking for distance from center, calculate combined distance from the two foci). Multiplying by a circular gradient would result in an island that doesn’t fill up the wide map, but an elliptical gradient worked like so:
I was pleasantly surprised by how good the island shape looked; I just felt like the outline was too smooth, so I added in some higher frequency noise to add smaller details. The values were 0 to 1 as explained earlier, so I just did perlin(x,y)*.9 + simplex(x,y)*.1 instead of only the perlin(x,y) values. The result was this island shape:
From here I just touched up the colors (eg. I had a few color ranges, instead of flat green once past the water level) to get the images at the top. The value at each pixel was already nicely varying and didn’t need any more massaging.