PotatoPie
PotatoPie

Reputation: 1

Minecraft like terrain in unity3d

I'm a fan of Minecraft's old terrain generation with amazing overhangs, mountains and generally interesting worlds. My problem is that right now I'm using perlin noise, which while good for smooth terrain doesn't really give sporadic jumps that would allow mountains in a mostly flat area.

On top of that with the method I'm using gets 2d perlin noise, puts it in an array and then gets every Y value under it and sets it to a block; This stops generation of overhangs like this: Old Minecraft Terrain Image

Right now I have this:

public class GenerateIdMap : MonoBehaviour {
     [Serializable] public class IBSerDict : SerializableDictionaryBase<int, byte> {};
     public int size = 60;
     public int worldHeight = 3;
     public float perlinScale = 15f;
     public int seed;
     public int heightScale = 10;
     public int maxHeight = 256;
     public IBSerDict defaultBlocks = new IBSerDict();
     void Start()
     {
         if (seed != 0) seed = (int)Network.time * 10;
         CreateMap();
     }
     byte[,,] CreateMap()
     {
         byte[,,] map = new byte[size, maxHeight, size];
         for (int x = 0; x < size; x++)
         {
             for (int z = 0; z < size; z++)
             {
                 int y = (int)(Mathf.PerlinNoise((x + seed) / perlinScale, (z + seed) / perlinScale) * heightScale) + worldHeight;
                 y = Mathf.Clamp(y, 0, maxHeight-1);
                 while (y > 0)
                 {
                     map[x, y, z] = GetBlockType(y);
                     y--;
                 }
             }
         }
         return map;
     }
     byte GetBlockType(int y)
     {
         SortedDictionary<int, byte> s_defaultBlocks = new SortedDictionary<int, byte>(defaultBlocks);
         foreach (var item in s_defaultBlocks.OrderBy(key => key.Key))
         {
             if (y <= item.Key)
             {
                 print(item.Value);
                 return item.Value;
             }
         }
         return 0;
     }  }

The GetBlockType function is new and for getting the default block at that height, I'll fix it up later but it works for now. If you instantiate a prefab at that vector3 you would see terrain. Can someone help me figure out how to make better terrain? Thanks in advance!

Upvotes: 0

Views: 2151

Answers (1)

LintfordPickle
LintfordPickle

Reputation: 411

Both of your problems should be tackled individually.

The first issue regarding the lack of variation in the generated values can usually be fixed in one of two ways, the first way is to modify the input into the perlin noise, i.e. the octaves and persistance and the second is to mix the output of multiple functions and even use the output of one function as the input to another. By functions, I mean Perlin/Simplex/Voronoi etc.

With the former method, as you mentioned, it can be pretty difficult to get terrain with interesting features over a large area (the generated values are homogeneous), but by playing with the coordinate range and octaves/persistance, it can be possible. The second approach is probably recommended however, because by mixing the inputs and outputs of different functions you can get some really interesting shapes (Voronoi produces circular crator-like shapes).

In order to fix the problem you are having with the overhangs, you would need to change your approach to generating the world slightly. Currently, you are just generating the height values of the terrain and assigning each of those values to give you the terrain surface only. What you ideally would want to do is, generate a pseudo-random value to use as a pass flag for each of the blocks in the 3d space (also those underground). The flag would indicate whether a block should be placed or not in the 3d world.

This is slower, but would generate caves and overhangs as you need.

Upvotes: 1

Related Questions