This workshop will introduce you to 2D map generation in lua language, with the help of LÖVE2D.
Here is an example of what you could obtain.
Map generation is a powerful technique used in many games to create map or parts of a map with algorithms. The method of creating data from algorithms is named procedural generation. It has been used in a lot of games, like The Elder Scrolls (most of them), Age of Empire, The Binding of Isaac, No Man's Sky, or the well known Minecraft.
You can find at the root of the repository three folders.
assets
basic assets to quickly bootstrap you generatorexample
example projectsrc
you already know ;)
To launch the generator, you obviously need to have lua and LÖVE2D installed. Then you can run love in the root of this repository with love .
and you can even give a specific seed to your generator with love . 8436
.
If somewhere you get lost, you can run the example project by running the start.sh
script in the example
folder and look at the sources. But if you want to enjoy this workshop I highly encourage you to write your own code! Don't just copy paste, at the end it's often a waste of time.
In the src folder, you can found the terrain.lua
file, it's in this file that you're expected to code. But feel free to look at the other files, you could learn some interesting stuff, like how chunks works.
game.lua
contains the main loop and handle rendering using the terrain:render
function. utils.lua
contains some functions that you could find useful.
Perlin noise is a algorithm that generate noise with a pseudo-random appearance, yet all of its visual details are the same size. It can be use in any dimensions. This function is only pseudo-random and not random, therefore it can be represented in a mathematical way since for an input A, it will always return an output B, thus f(A) = B.
You can find a function utils.noise(x, y)
in utils.lua
, this function wrap a 3D perlin noise from LÖVE2D, the third dimension being used as a seed. The function takes two parameters which are the coordinates of the point to generate from the perlin noise. It can easily be used in terrain:render(x, y)
, since they share the same prototype.
Now that we know how to generate noise, it's time to render it! You just have to return the color that you want at the position (x, y)
in terrain:render
, just like that return 0, 0.7, 0.3
. The values should stay between 0 and 1.
A pretty easy way to debug your values is to use the function utils.valueToPixel(value, min, max)
. It takes a value
and return a pixel in gray scale with black being min
and white being max
.
Let's generate an island! To do so, let's imagine that the noise that we are generating correspond to the altitude of our map, with the sea level being 0.75, so 75% of our map will be water, the remaning 25% being earth.
You can use the fonction utils.pixelFromTexture(x, y, texture)
to get a pixel from a texture of terrain.assets
. Try to render either water or grass depending on the altitude. You can also merge easily two textures with utils.mergeTextures(x, y, t1, t2, ratio)
You should get a pretty wierd result for now but as you can see, there is water and grass. But maybe you would like something looking more like islands. First of all, you could use several noises with different scales as described here. You can combine them in several ways depending on what you are trying to do, by sum, by average, by multiplication.
You can also apply modifications on noises, maybe adjusting the contrast with utils.contrast(value, factor)
, it's a mathematical function represented as contrast(value, factor) = (value - 0.5) * factor + 0.5
.
Once you got fine results, you may want to add some more details. You could try to use one more noise to generate temperature, that you can use to adjust colors consequently with a blue shift when it's cold, and a red shift when it's hot. You could also generate some snow on montains or icebergs in the ocean. On the same model, why not trying to generate humidity ?
And what about biomes ? Now that you have temperature and humidity, you could try to define conditions on those both parameters to determine in what biome you are ! Let's imagine that we have two axis, the temperature is on the X axis and the humidity on the Y one. You can define a surface on the graph that describe a biome like on this one from wikipedia.
Well, it's now up to you to continue to tweak your generator, add new rules, and maybe even trying to generate maps in 3 dimensions ?
- Understanding perlin noise
- Making maps with noise functions
- The book of shaders: Noise (available in many languages including french)
- Fantasy map generator - a webapp that help you creating map for fantasy worlds
- Polygonal Map Generation for Games
- Procedural Terrain Generation With Voronoi Diagrams
- The book of shaders: More noise (available in many languages including french)