Hey hey!
So we’ve created rivers in last part right? Now that we have elevation and river , now we can calculate moisture which we’ll use for biomes later. I guess this will be a short post , since calculating moisture is pretty much same as calculating elevations. Pretty similar iterations , almost same.
The main idea here is to set river moisture a static value and then iterate through all corners and decrease this value as the corner gets further away from the river. Then we’ll also set center ( polygon ) moisture as the average of it’s corners’ moisture , easy peasy.
OK so I’ll start with our first method , CalculateCornerMoisture() }
private void CalculateCornerMoisture()
{
var queue = new Queue<Corner>();
foreach (var q in App.AppMap.Corners.Values)
{
if ((q.Water || q.River > 0) && !q.Ocean)
{
q.Moisture = q.River > 0 ? Math.Min(3.0, (0.2 * q.River)) : 1.0;
queue.Enqueue(q);
}
else
{
q.Moisture = 0.0;
}
}
while (queue.Count > 0)
{
var q = queue.Dequeue();
foreach (var r in q.Adjacents)
{
var newMoisture = q.Moisture * 0.9;
if (newMoisture > r.Moisture)
{
r.Moisture = newMoisture;
queue.Enqueue(r);
}
}
}
foreach (var q in App.AppMap.Corners.Values)
{
if (q.Ocean || q.Coast)
{
q.Moisture = 1.0;
}
}
}
As you can see we got 3 simple loops here. I won’t go into the detail as they are pretty much self explanatory.
First we iterate through all corners , set rivers moisture to 0.2 * river size ( maximum 3.0 ) and then add those river corners to the queue.
Then we start processing stuff in the queue , for each corner in the queue , we find it’s adjacent and set moisture to the 0.9 of original value. So with each step , moisture is decreased by 0.1 of the closest river moisture.
Then at last we set ocean and coast moisture to a standard value , 1.0.
I’m using a little different method in my personal project , merging 1st and 3rd loop together.
{
q.Moisture = q.Water
? 1
: ( q.River > 0
? Math.Max(3.0, (0.2 * q.River))
: 0.1 );
queue.Enqueue(q);
}
It does pretty much the same thing , just in one loop and I don’t think setting ocean moistures before effects much or anything at all.
Anyway , once we set corner moisture…. actually we’re almost done.
Amit prefers to redistribute moistures as well ( remember we did the same thing for elevation before ) I personally prefer not to do this but here it is ;
private void RedistributeMoisture()
{
var locations = App.AppMap.Corners.Values.OrderBy(x => x.Moisture).ToArray();
for (int i = 0; i < locations.Count(); i++)
{
locations[i].Moisture = (float) i/(locations.Count() – 1);
}
}
I added this to the sample solution below but it creates a very low moisture / desert-ish island for me at the moment , so it’ll be commented out. But remember all this stuff is just about some static variables. I know it’s a very bad practice but you’ll see magic numbers around , like 3.0 being the maximum river moisture , in that method above. All you have to do play with such numbers until you got an island you like.
One last thing before we finish , setting center ( polygon ) moistures. As I said before we’ll just take the average of corners and use it as center moisture , so it’s simple as this ,
{
c.Moisture = c.Corners.Sum(x => x.Moisture) / c.Corners.Count();
}
Aaand we’re done! Now when you run it , it should look something like this ,
Not bad eh? Well actually we’re pretty much done now , at least code-wise. There is only biome selection left and that’s not really a technical issue , also it’s in the sample solution since the Part 2 , as we needed to visualize it somehow. Still I may post about it in the future , or maybe some other stuff like the methods I used etc.
I really hope you liked it or at least found useful. I’m still working on this occasionally so I’ll probably post about it in the future again , maybe even about the XNA version of it.
You can find the sample solution file below , please don’t hesitate to contact me for any questions!
Visual Studio 2010 Solution
Your rivers look great!
For a long time I didn't redistribute moistures. I added the moisture redistribution at the very end of the project. I had previously balanced all the magic numbers to produce a reasonable distribution of wet and dry areas, but those magic numbers didn't work when I changed the size of the map or changed other parameters. (Yes, I use lots of magic numbers even though I know I shouldn't.)
Instead of tweaking magic numbers repeatedly, I decided to force an even distribution of moistures. It reduced the variety a bit but it also got rid of magic numbers and many bad maps. I think if I were doing it again and wanted more variety I might pick from many distributions instead of always distributing them evenly.
One bug I had run into when redistributing moistures is that half the map is ocean, and ocean moistures are high, so all the remaining land moistures end up dry, resulting in deserts. To fix this I made a list of the land areas only, and then redistributed moistures for only them. I haven't studied your code closely but I think you might have the same bug.
Hey Amit!
Now I see why you did it like that , and honestly calculating moisture was pretty hard/tedious work. I tried lots of variations but even smallest changes can totally change the biome of whole island. In the end I found myself wasting hours tweaking some floats and was pretty pissed.
I kinda took a break from this project for now , I'm pretty satisfied with the 3D XNA version so trying some other stuff ( like dungeon generation and regular business applications ) at the moment.
http://i.imgur.com/iv8JI.png
Tried 3D vegetation a bit but it was hard to find a 3D artists so gave up on that. Also smoothed the rivers yet didn't liked that. Oh well , I'll go back to this one if I ever find a good improvement idea.
Hey Amit, what VS color theme are you using?
Well guess that was directed at me?
I'm using "Son of Obsidian" theme, which you can find here ;
http://studiostyl.es/schemes/son-of-obsidian
All code samples posted in my blog posts uses that theme too.