I use Mathf.PerlinNoise
to generate grass/water in a 2d square. It works as intended, however I am not really getting very interesting water, and at times it can look very bare or unrealistic, here is a sample of a bad generation:
Unfortunately it took me about 20 tries to find an interesting one, what I want is something along these lines:
Or something like this, but I don't want any tiny areas of water:
You can copy/paste the components below and try urself with 1x1 cubes (if you don't have Odin just delete that part):
using UnityEngine;
using Sirenix.OdinInspector;
public class GenerateMap : MonoBehaviour
{
[Range(0, 40)]
public int mapWidth = 20;
[Range(0, 40)]
public int mapHeight = 20;
[Range(0, 20)]
public float noiseScale;
[Space]
public GameObject parent;
public GameObject grassTile, waterTile;
[Button("Generate map")]
public void GenerateMap()
{
for (int i = 0; i < parent.transform.childCount; i++)
{
Destroy(parent.transform.GetChild(i).gameObject);
}
float[,] noiseMap = Noise.GenerateNoiseMap(mapWidth, mapHeight, noiseScale);
for (int x = 0; x < mapWidth; x++)
{
for (int y = 0; y < mapHeight; y++)
{
Debug.Log(noiseMap[x, y]);
if (noiseMap[x, y] >= .3)
Instantiate(grassTile, new Vector3(x, 0, y), Quaternion.identity, parent.transform);
else
Instantiate(waterTile, new Vector3(x, 0, y), Quaternion.identity, parent.transform);
}
}
}
}
Noise:
using UnityEngine;
public static class Noise
{
public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, float scale)
{
float[,] noiseMap = new float[mapWidth, mapHeight];
Vector2 offset = new Vector2(Random.Range(0, 100), Random.Range(0, 100));
if (scale <= 0)
scale = .0001f;
for (int y = 0; y < mapHeight; y++)
{
for (int x = 0; x < mapWidth; x++)
{
float sampleX = x / scale + offset.x;
float sampleY = y / scale + offset.y;
float perlinValue = Mathf.PerlinNoise(sampleX, sampleY);
noiseMap[x, y] = perlinValue;
}
}
return noiseMap;
}
}