- Home /
Better perlin noise map generation.
I written my own code (see below) for generating a perlin map using a seed value, and then spawning resources and using a second perlin map to spawn, and then spawn water tiles. This system works, and my perlin noise is "zoomed in". However, the problem is, sometimes, the terrain looks good, but from time to time, some water tiles will just spawn by itself, or sometimes create a bad shape which doesn't look good. I know perlin map is used for pseudo random map generation however, I do want to control it for example, making everything that is just a straight line by itself not spawn or erased, or some water tiles that is just by itself to not spawn. Here's the code:
static public void GenerateMap(GameObject[] resources, int seed = 0)
{
//Instantiate Gridmap.
gm = new GridMap(mapWidth, mapHeight, 1);
if (seed == 0)
{
seed = Random.Range(0, 999999);
}
print(seed);
//Instantiate the first perlinNoise map.
noiseMap = new PerlinNoise(mapWidth, mapHeight, seed, TerrainSpawnScale);
//Generate terrain (water) onto the map.
TilemapController tmC = FindObjectOfType<TilemapController>();
for (int i = 0; i < mapWidth; i++)
{
for (int j = 0; j < mapHeight; j++)
{
Vector2 currentSpawnPos = gm.origin + new Vector2(i, j);
if (Vector2.Distance(gm.WorldPosToGridPos(playerSpawnPoint), gm.WorldPosToGridPos(currentSpawnPos)) > playerSpawnNoResourcesRange)
{
if (noiseMap.noiseValueAt(i, j) > TerrainSpawnRate)
{
Vector3Int tileCoord = new Vector3Int((int)currentSpawnPos.x, (int)currentSpawnPos.y, 0);
tmC.setTerrainTile(tileCoord);
gm.terrainOccupations[i, j] = true;
}
}
}
}
//Instantiate the second perlinNoise map.
noiseMap = new PerlinNoise(mapWidth, mapHeight, seed, ResourcesSpawnScale);
//Loop through the entire map and generate natural resources based on the perlin noise map generated.
for (int i = 0; i < mapWidth; i++)
{
for (int j = 0; j < mapHeight; j++)
{
Vector2 currentSpawnPos = gm.origin + new Vector2(i, j);
if (Vector2.Distance(gm.WorldPosToGridPos(playerSpawnPoint), gm.WorldPosToGridPos(currentSpawnPos)) > playerSpawnNoResourcesRange)
{
if (noiseMap.noiseValueAt(i, j) > ResourcesSpawnRate && !gm.getTileOccupation(new Vector2Int(i, j)))
{
GameObject resource = objectToSpawn(resources);
Instantiate(resource, gm.WorldPosToGridPos(currentSpawnPos), Quaternion.identity, GameObject.Find("NaturalResources").transform);
//Set up Gridmap's terrainOccupations
}
}
}
}
}
PerlinNoise is a class I created:
public class PerlinNoise
{
private float[,] noiseData;
public PerlinNoise(int mapW, int mapH, int seed = 0, float spawnScale = 1)
{
if (seed == 0)
{
seed = Random.Range(0, 999999);
}
noiseData = new float[mapW, mapH];
for (int i = 0; i < noiseData.GetLength(0); i++)
{
for (int j = 0; j < noiseData.GetLength(1); j++)
{
float xCoord = (float)i / (float)mapW * spawnScale + seed;
float yCoord = (float)j / (float)mapH * spawnScale + seed;
noiseData[i, j] = Mathf.PerlinNoise(xCoord, yCoord);
}
}
}
public float noiseValueAt(Vector2Int pos)
{
return noiseData[pos.x, pos.y];
}
public float noiseValueAt(int w, int h)
{
return noiseData[w, h];
}
}
If you have any suggestions on how I can improve my code I'll appreciate it.