Saturday, July 15, 2023

Biome Generation

Until I have made final decisions about the core of the game, I knew that either way I will need to generate the map. As a lonewolf, it would be impossible for me to make large landscapes and manually sculpt it all, or even decorate with structures and items. If I plan to have large landscapes then I need to procedurally generate the landscape as much as possible.

My plan is to start with the Biomes. I want multiple biomes for the world; Oceans, Plains, Deserts, Forests, and Rocky Mountains. I also want Rivers throughout the lands, and high elevation Snowy Mountains. It all sounds great, but I need to get it done.

My idea was to generate an array of integers, based on a seed, and then perform blends with those integers. Each integer can represent a biome type. Zero for ocean, 1 for plains, 2 for deserts, and so forth. Let's start with just an empty map and generate a simple 0 or 1. 0 will be land, and 1 will be water.


I know it's really small, but I wanted to use a simple example to ensure everything is working fine. We have a small 16x16 image that represents the 0's and 1's generated from a seed. With simple math a 0 turns into the color black, and 1 turns into the color white. Here it is again but turning the 1's into a blue color to more clearly represent the water.


The concept seems simple enough. Now I want to manipulate this data, and I can do so in multiple ways. Essentially, while iterating through each data point (or pixel, as represented as an image), I can perform calculations, I can get neighboring data points and perform calculations together (an example is interpolating between the points for smoothing), and it becomes even more useful as a class.

As a class these can be considered Layers, and layers can be combined and/or they can perform specific actions to its own data, or in combination with another Layer's data. That was hard to write, but I hope it makes sense. Otherwise, I will write up a more technical article than this, as this is mostly just to present my progress, and share results.

For example, I created the initial map data as before, and called it "Island* island = new Island(1);" (a value of 1 in the parameter means to use the original seed, or seed * 1). Then I created another class, which extends BiomeLayer, and it creates map data using the island data; "Plain* plains = new Plain(1, island);" At this point, plains is my main map data, since it combines the island data with itself. However, this will give me the same results as before, so I'm going to add another layer; "Forest* forest = new Forest(1, plains);" - now to clarify:

I created a map with simple land/water data. I created another map, using that data, and assigned the biome type "Plains" to the land portion of the data. I created another map that uses the combined (land/water/plains) map data, and blends into the plains data the forest biome data. Each biome type is its own class, and can perform biome specific calculations to the set of data generated and/or given.

I increased the size to 256x256 so that there is more data to work with, and so it's easier to see on here. I started making "official" colors, so the water is blue, the plains are green, and the dark green is the forest. I had taken the color pallette from a Google search. These colors are only for representation of the data, but at the end of the day my game only needs the data as integers. These integers are just manipulated to determine the color of the pixels.


Now this looks way more fun! If this is all I wanted for my world then I would be set, but I want larger land masses, and oceans. This data is great, as you can see when you zoom into the map, these would be a lot of islands. I need to create a layer that handles zooming so that we can just capture a portion of the data, and then work with those results. Draw imaginary lines subdividing this square, and then imagine each of those as a "zoom," but we could do even more calculations depending on what we want to do, and then combine results.

For now, I'm having fun, and I'm going to add deserts.

Too much desert, but it works! The desert had taken over, so I will need to control that, or maybe just blend another plains layer. Time to work on zoom in-out, smoothing, and then I can have a smoothed zoom layer. I want to add more biomes as well so I can continue tweaking values and parameters.


I increased the size to 512x512. Zooming overall makes the water look like larger bodies of water, but it's still not good enough. What I could do is add a layer that removes the smaller "bodies of water" and then maybe increase the remaining water. I also didn't mean to use that color for the plains biome (maroon color). This pass was also an attempt to reduce the amount of deserts.

That's better!

Not nearly as much desert now, and I mostly just added another layer of plains. Time to work on the oceans, and add more functionality to the zoom, smooth, interp., etc., functions of the layers.


Better, but kind of ugly. This almost makes me want to stop, but there is progress to be seen beyond the ugly. There are too many biomes smashed together for my eyes. The "Mesa" and "Snow" biomes are added, and thankfully they didn't take everything over like the Desert. The Mesa had kind of taken over in the areas I would like for there to be Ocean. Maybe I can take advantage of that, and maybe smooth out the biomes. I should use a "temperature map" to help determine biomes. Hot environments would have more desert, and cold environments will have more snow. The biomes need more space between them, and that could help organize the "land masses." I will create a temperature layer, or maybe just add a set of temperatures for the biomes, and compare temperatures when deciding biomes.


Definitely getting better. I'm not sure what's happening with the Mesa biomes. I believe the data is correct, but how I'm determining colors and saving the results as a PNG may be the culprit. The results are at least decent, but I will check the color output soon.


Well now I've done it! I don't know what I did to deserve these results. The red lines are an attempt at rivers but there are issues. The obvious one for me is, well, they shouldn't be red! This also looks zoomed by a hundred times. Time to troubleshoot my code, and my math; probably my life.

What have I done?!

It's like the biomes got scared and left. Obviously, I messed up the layers, and I must have overwritten the main layer right before exporting the image. At least I hope.

Okay...

Obviously it's something layer related. Time to triple-check my math, and I'm just going to rewrite the layers starting with the first land/water layer, temperature map, sigh.. Here we go...

SUCCESS!

There are biomes missing, but this is what I'm looking for! I will continue, but I would be more than happy to return to these results. This is exactly what I need to generate the landscape in Scavenge.

Multiple issues were the cause of the odd results earlier. I didn't show the results before this one, where it looked like the result with the red river lines (they were red again, so I looked at how I was creating the PNG data), and that result forced me to go over all of the biome classes with a fine-toothed-comb. I found many errors, some in my math on neighboring data points, and there was even an error in my function that selected random biomes after examining neighbors to determine its potential biome types.

I'm going to examine the missing biomes, but some are not present on purpose. I needed to figure out what was going on, and that was best with just a few biome layers. Also, did you notice the shore lines? That was easy to calculate since a data points neighbors had to be both "ocean" and any biome type. I had taken it further and made "frozen beach", "cold beach", "rocky beach", and a normal "beach".

I need to wrap up this article, so time to get back to work.

I've generated a 2048x2048 of the final results. I am more than pleased!


Welcome to seed 7 of the upcoming landscape in Scavenge. The biomes are no longer staggered unorganized patterns because they adhere to a temperature map. It no longer has a snowy plain right next to a jungle as an example. It's more organized and looks more natural.

A quick note before ending this article:

If each pixel was 1 block in the game there would be 4,194,304 blocks!

Thanks for reading!


No comments:

Post a Comment

3D Landscape Basic Textures

 I thought I would add a couple textures so it wasn't just white. This is by no means a representation of what the landscape will look l...