World Gen

Thoughts on the further development of Haven & Hearth? Feel free to opine!

Re: World Gen

Postby Peter » Tue Jun 09, 2009 7:25 pm

The large map is rendered on the scale of pixel = tile.

It is very true that fractal landscapes have scaling difficulties; this is because real landscapes are not uniform fractals. That is, mountains, hills, plains, and coastlines all form via different processes. No one equation can cover all of these. What I've done with mine is used several different "fractals" (well, actually one crude fractal that is distorted differently several times) and blended them together; Coastlines are defined by one pattern, forests by annother, swamps by a third. It is also possible to have one pattern influence annother, such as having places close to shore be more likely to become swamps, or conceivably have areas far from swamps potentially become dry dirt. I could even have forests cause landscapes to raise up.

Luckily for us, the current tile system actually does a good job of hiding artifacts; even the crude current map looks kind of good from in-game.

Take a look at the large map and zoom in to see what the in-game map would be like; each pixel is one tile.
Surprise.
User avatar
Peter
 
Posts: 1491
Joined: Thu Jun 04, 2009 3:36 am

Re: World Gen

Postby Vattic » Tue Jun 09, 2009 7:35 pm

If that is the case then I would love to see one of your maps rendered by the games engine and then posted up here :D.
User avatar
Vattic
 
Posts: 232
Joined: Sat May 30, 2009 1:47 am
Location: United Kingdom

Re: World Gen

Postby Peter » Tue Jun 09, 2009 11:45 pm

I'd like to see that myself, but I don't have the knowledge here. I would like to know how map information is saved, and then I might be able to make a more importable map format. Of course, the generator it'self could be built into the server, which would allow live map growth, and allow the server to "forget" old areas and regenerate them exactly as they where before!

A small area 1px=1tile (roughly):
Image

Latest worldish map:
Image

Now, to demonstrate the scale of this map:
Image
Image
Image
Image
Image
Image
Image
Now, the remarkable thing is each and every inch of even the largest map can be generated on the fly, and with perfect accuracy. Of course, over very large scales the world becomes homogeneous, but it is possible to change the generator slightly to add annother layer of complexity that can resolve even that.
Surprise.
User avatar
Peter
 
Posts: 1491
Joined: Thu Jun 04, 2009 3:36 am

Re: World Gen

Postby theTrav » Wed Jun 10, 2009 1:20 am

There's a video? I can't see it.

I also didn't realize how the procedurally generated bit worked, that's pretty neat. Are you a programmer? If not I might try to bang up something that just plonks down H&H tiles based on those image files just to see how it goes.


As for the "recognising areas / forests" I still reckon the game should assign forest tiles based on the density of trees in the area rather than have pre-determined forests. The map gen should only be able to specify areas where trees find it very difficult to grow (desert, swamp, maybe steppe & mountain if they do that).
User avatar
theTrav
 
Posts: 3464
Joined: Fri May 29, 2009 11:25 pm

Re: World Gen

Postby Peter » Wed Jun 10, 2009 6:51 am

If you are familiar with DF terms, I am a dabbling Programmer.
There's a link to the video on the first page. I have a colossal 30 second clip that I'll try to downconvert to something portable, but take a look at the earlier clip to see some of the stuff you can do with some parameters.

I'd be glad to share what I've got.

The key thing is the noise generator- a random heightmap or fractal that- and this is key- has consistent slopes. This is opposed to a really noisy heightmap where each pixel has a random value with no connection to adjacent ones. That is:
Image
(Note that red is extreme highs, blue extreme lows, Greens for elevation lines.

Then, you scale it down, shift it and add it to original pattern so that the larger noise has finer details from the smaller noise. This process can be repeated several times so as to have many levels of detail. In my map I have two levels for most terrain features.

Then we can simply create a slightly different grayscale for each terrain type, then cause interactions between terrains (for instance, add 0.2 to swamp when elevation is at 0 and subtract 0.2 from it at elevation at 1). Once you have the final grayscale map, at any point that is higher than X, make it 1, else 0. The effect is that you'll have this nice, organic looking terrain borders like I have above. Some terrain might need more detail (for instance, the high-contrast change from water to land means that there should be one or two extra layers for it on the greyscale. X can be selectable, and small changes can cause more or less of the relevant terrain to be present. Finally layer each terrain pattern on top of each other and there's your map.

Now, for a better system, you could compare all maps at each point and select what is most intense at any point rather than just culling, but I don't know how that would look for you.

Here's the "source code", as it's built in art of illusion, so it's not getting out of there.
Image
Trust me, that's actually pretty good for what we're working with.

Oh, there's one more thing that I've discovered, and that is that real terrain has a non-linear, non-sine distribution- that is, most terrain is slightly above or below water, with exponentially less terrain at higher elevations. I figured out that if you're starting with a noise patten that's linear, like the one I have at the top of this post, that you just need to decrease the prevalence of extreme values and increase common ones, something like an inverted sine curve. for the actual data (which isn't all that useful, but interesting nonetheless).

Heh, I didn't realize it, but I invented procedural brownian motion...
Surprise.
User avatar
Peter
 
Posts: 1491
Joined: Thu Jun 04, 2009 3:36 am

World Gen: Now with CODE!

Postby Peter » Thu Jun 11, 2009 4:43 am

Code: Select all
//Peter Cymbalski; Nowhere Publishing Browninan Layer Map Generator v0.05
#include <iostream>

using namespace std;

//The Index:
   float fractalMap(int,int,int);
   int mapLayer(float,float,float,float,float);
   void textout(int);
   float floatcap(float);

int main()
{
   cout << "NWP BLMG (c) Peter Cymbalski\nPlease enter the X co-ord.\n";
   int iXin;
   cin  >> iXin;
   cout << "Please enter the Y co-ord.\n";
    int iYin;
   cin  >> iYin;
   float fFracElvtn = fractalMap(iXin, iYin, 1);
   float fFracSwamp = fractalMap(iXin, iYin, 2);
   float fFracSand  = fractalMap(iXin, iYin, 3);
   float fFracForst = fractalMap(iXin, iYin, 4);
   float fFracClay  = fractalMap(iXin, iYin, 5);
   return(0);
}

float fractalMap(int mapX, int mapY, int mapOffset)    //mapX and mapY refer to the xy coords of the tile in the world. "Browninan" refers to Fractoral Browninan Motion, the basis for this generator.
{
   //Offest adjustments:
   mapX = mapX+(mapOffset*100);
   mapY = mapY+(mapOffset*100);                        //*100 so that small values for mapOffset radically change the part of the noise we're looking at

   //Generator fine-tuning: Universal for all layers, an improved but bulkier version may add these as variables
   float  fScaleLevelA = 1;                           //Defines the scale of the top layer of each Noise map
   float  fIntenseLevelA = 1;                         //Defines the intensity of the top layer of each Noise map
   float  fNLevelB = 2;                        //As above, for next layer intensity and scale.
   float  fIntenseLevelB = 0.5;
   float  fNLevelC = 4;
   float  fIntenseLevelC = 0.25;
   float  fLA = 0, fLB = 0, fLC = 0;
   float  fTotalHeight = 0;

   //Combines, or "draws" the map layers and scales them:
   fLA = ((Noise(mapX*fScaleLevelA),(mapY*fScaleLevelA))*fIntenseLevelA);                      //Draws and modifies layer A
   fLB = (((Noise(mapX*fScaleLevelB),(mapY*fScaleLevelB))*fIntenseLevelB)-(0.5*fIntenseLevelB));    //Draws and modifies layer B, Displaces it for next step
   fLC = (((Noise(mapX*fScaleLevelC),(mapY*fScaleLevelC))*fIntenseLevelC)-(0.5*fIntenseLevelC));    //Deaws and modifies layer C, Displaces it for next step
   fTotalHeight = fLA+fLB+fLC;
   fTotalHeight = floatcap(fTotalHeight);
   return(fTotalHeight);
}

int mapLayer( float fElevation, float fSwamp, float fSand, float fForest, float fClay)
//BIG NOTE HERE: Replace magic numbers with variables that allow map customization, eventually
{
   //subsection: transform terrain due to others. Lots of magic numbers here, but kind of unavoidable. These numbers should come from a config file, really.
   float fElevSea = (fElevation-0.5); //Height above sea level.
   if (fElevSea < 0) fElevSea = 0;
   fElevSea = floatcap(fElevSea * 2);
   fSwamp  = floatcap(fSwamp-((0.4*fElevSea)-0.2));
   fSand   = floatcap(fSand-((1*fElevSea)-0.95));
   fForest = floatcap(fForest-((0.1*fElevSea)-0.05));
   fClay   = floatcap(fClay+((0.4*fElevSea)-0.2));

   //subsection: select tile.
   int iTileOut = 0;
   //Threshold variables. Magic Numbers good for changing later.
   float fThElev = 0.5;
   float fThSwmp = 0.5;
   float fThSand = 0.5;
   float fThFrst = 0.5;
   float fThClay = 0.5;
   if (fClay > fThClay)   iTileOut = 5;
   if (fForest > fThFrst) iTileOut = 4;
   if (fSand > fThSand)   iTileOut = 3;
   if (fSwamp > fThSwmp)  iTileOut = 2;
   if (fElevation < fThElev) iTileOut = 1; //supposed to be reversed; if it's less than a value, it's under water!
   return(iTileOut);
}

void textout(int iTerrainout)
{
   if (iTerrainout = 0) cout << "Tile is grass.\n";
   if (iTerrainout = 1) cout << "Tile is water.\n";
   if (iTerrainout = 2) cout << "Tile is swamp.\n";
   if (iTerrainout = 3) cout << "Tile is sand.\n";
   if (iTerrainout = 4) cout << "Tile is forest.\n";
   if (iTerrainout = 5) cout << "Tile is clay.\n";
   return();
}

float floatcap(float x)
{
   if (x < 0) (x = 0);
   if (x > 1) (x = 1);
   return(x);
}

Now what I need is to implement a nice Perlin or Simplex here under the "noise" function. Unfortunately such code is kind of tough.
The goal would be to have a function you could simply call with X and Y coords, and have that return from 0-5 with the tile type.
I think my buddy can transpile this from C++ to Java. What's your server based on?

Now, the way you might use this is that every time someone gets near the current map edge, the server generates a 100x100 area, spawns trees, rocks, and rivers as appropriate for the underlying terrain, and sticks this onto the map. You can even unload and entirely forget areas that haven't been visited in x hours and regenerate them later exactly the same (admittedly loosing things like constructions.
Surprise.
User avatar
Peter
 
Posts: 1491
Joined: Thu Jun 04, 2009 3:36 am

Re: World Gen

Postby jorb » Thu Jun 11, 2009 6:01 am

@ Peter: Very impressive.
"The psychological trials of dwellers in the last times will be equal to the physical trials of the martyrs. In order to face these trials we must be living in a different world."

-- Hieromonk Seraphim Rose
User avatar
jorb
 
Posts: 18436
Joined: Fri Apr 03, 2009 7:07 am
Location: Here, there and everywhere.

Re: World Gen

Postby Peter » Thu Jun 11, 2009 5:31 pm

I saw your new sticky comment, and I understand what you mean. I'll probably continue working on this because I like the concept, but if you aren't interested I'll stop posting it here.

The code I posted up there is non-functional, but just to be on the safe side, I want to say that I relinquish any rights to the code sample I provided, blablabla, I can't sue you just because I think you have used that particular code, even if you should decide to profit from it.

This does not include any derivations of that code that I might make at a future date, and should you like to work with me in the future, I'd be glad to discuss a more formal agreement.

So, to summarize this whole thread:
"Consider generating world maps using Perlin or Simplex noise as a basis of Fractal Brownian Motion to generate terrain procedurally, as this would allow expandable and consistent maps."

P.S.: There is a way to use such fractals to make tiling or looping areas- thus, you could conceivably make a cylindrical world (impassible or infinite to the north, e-w passage), a toroidal world, or even a spherical world... somebody mentions something...
Surprise.
User avatar
Peter
 
Posts: 1491
Joined: Thu Jun 04, 2009 3:36 am

Re: World Gen

Postby loftar » Thu Jun 11, 2009 7:43 pm

I have a few reactions on this;

On the one hand, I had not considered the idea of fractal landscape generated functionally, but it is of course true that such generation would make it extensible. It is a fascinating idea, and I may well explore it. Thank you!

On the other hand, there are a few other features planned in the map generator that are far from obvious how they would be implemented in a fractal landscape. It may not be completely impossible, though, and I'll keep considering it.

At the very least, I may well take the time to load your map into an alternative world so that I can explore it on a tile-scale and see what it looks like.
"Object-oriented design is the roman numerals of computing." -- Rob Pike
User avatar
loftar
 
Posts: 9045
Joined: Fri Apr 03, 2009 7:05 am

Re: World Gen

Postby Raephire » Fri Jun 12, 2009 10:20 pm

I saw the current ocean and it made me very sad.

BUT! The game, even at this stage, is just so absolutely intoxicating that It's a detail I can neglect.
User avatar
Raephire
 
Posts: 648
Joined: Wed Jun 10, 2009 3:34 pm

PreviousNext

Return to Critique & Ideas

Who is online

Users browsing this forum: Claude [Bot] and 2 guests