Some days ago, I tried to create a procedural landscape generator. Here is the actual result: https://rap2hpoutre.github.io/landscape-site/
I like to know how things work; this is how I built that one.
I’m not a good programmer and I don’t know how to create mountains. I found this answer on Stack Exchange: https://gamedev.stackexchange.com/a/93531/81351
So, I transposed this code into Rust, because I do like Rust for reasons. First, I created a Mountain
struct.
The points
are the “y” position of each summit: on a 640x480 image, there are 640 points varying from 0 (highest) to 480 (lowest).
Then I created two associated functions: a new
method to initialize points and a draw
method to render each pixel of the mountain range.
It’s the longest part (it’s dirty, not the ugliest though!), think it’s just an adapted copy/paste from the StackExchange post I mentioned.
The new
method takes a tuple of arguments y_amp
which is just the bounds of the current mountain range (max height and min height). The points are initialized with random adjacent values.
The draw
method takes a reference to the image we are drawing on and two colors: the initial color of the mountain range (color
) and the color of the fog (c_fog
) which is required in order to create a gradient. For each point
, draw a gradient “line” form the summit to the bottom of the image, mixing fog color with initial color.
I could have use constants (for 640, 480, etc.), choose better name for variables and add comments but, hey! No time! Be quick, be dirty.
The main task of this program is to generate random colors. I created a small helper to generate a color:
I forgot to mention that all functions and structs like _Rgb_
, _RgbImage_
, _interpolate_
, etc. comes from the excellent, partially documented and more or less stables “image” and “imageproc” crates (a crate is a Rust lib).
The rgb_rand
function I wrote can generate a random color from red range, green range and blue range. I will use it everywhere from now.
With the help of rgb_rand
function, I can initialize a random sky color, a random fog color, and a random moon color.
The sky. It can be light, dark or light-blue, let’s throw 1D3:
The fog has a totally random color and the planet (moon? sun? who cares?) color is a mix between the sky and a random color:
Now let’s draw everything. So I started with the sky (our base image buffer):
Then the program draws the planet as often as not after throwing a coin with gen_weighted_bool
. The planet is just a filled circle. Sometimes, another filled circle is drawn just after with the color of the sky to create a crescent moon effect.
Then a gradient is applied on everything we drawn.
With all this code in a main function, we now have a gradient sky with a moon.
It’s time to add some mountains ranges on this gradient sky.
In short, I just defined a random number of mountain range mountain_count
, then a base color c_mountain
. Then we iterate for each mountain range, build and draw the Mountain
we created on the first step.
The deep down mountains have their color softened with the sky color. Remember the fog color is also mixed with the mountains to make them seems less flat.
Maybe I forgot something, the whole code is available here: https://github.com/rap2hpoutre/landscape/blob/master/src/main.rs
I love procedural generation and I love to read about how procedural things were created, even if I don’t understand most of the time. This post is a description of what I coded, it’s obviously not a how-to or a tutorial about Rust. The result is not super-sexy, but I liked creating it. I also built a small web site with a fresh landscape generated every minute. In a frame, because I wanted it look like artistic! Here it is: https://rap2hpoutre.github.io/landscape-site/
My main inspiration were Navarre mountains. Here is a list of projects far better than mine, also I plundered their ideas:
I would be happy to answer questions, listen to suggestions or face criticisms.
Thanks to @dorhan_ for his review!