EDIT: I've tried this with Perlin Noise with no success, then with Voronoi diagrams, and now I'm editing the question to reflect the issues I had with Perlin Noise, trying again.
I'm developing a game in Unity and trying to build a map generator that is capable of creating random maps like the Earth, on a 2D tilemap. The map should contain 2 types of tiles (let's call them grass and ground), while the grass should be the "main" tile, and there should be islands of ground on top of the grass.
This was already asked here. My purpose is to create something like the second picture in the question (that picture is showing water and grass, but it doesn't really matter).
This blog post suggested a simple way to fill a map (2d array) with Perlin Noise values (float numbers between 0-1), which I did. Eventually each value was rounded to 0 or 1 to present a grass or ground tile.
What I can control now is the frequency of the noise, but it's not enough.
The map generated by the code below: (frequency of 0.3)
The problems with this method:
- No randomness. I know Perlin Noise is NOT a random function, so how can I add random factors to generate a different map each time?
- How can I control the number of islands (e.g.: with a factor that can determine "more islands" or "less islands", not an approx. number)?
- How can I control the size of each island (again, with a factor. I don't care about exact size)?
My code: (C#)
using System;
using UnityEngine;
using UnityEngine.Tilemaps;
using Random = UnityEngine.Random;
namespace TankMayhem {
public class GroundTilemapGenerator : MonoBehaviour {
private const string TilesPath = "Tiles";
private Tilemap tilemap;
private TileBase[] possibleTiles = new TileBase[2];
private void Awake() {
tilemap = GetComponent<Tilemap>();
var tiles = Resources.LoadAll<Tile>(TilesPath);
possibleTiles[0] = Array.Find(tiles, tile => tile.name == "ground");;
possibleTiles[1] = Array.Find(tiles, tile => tile.name == "grass");
int i;
int j;
int[, ] map = new int[tilemap.size.x, tilemap.size.y];
const float Frequency = 0.3f;
PerlinNoiseCave(map, Frequency);
float[] probabilities = new float[2];
foreach (var position in tilemap.cellBounds.allPositionsWithin) {
i = position.x;
j = position.y;
var tile = possibleTiles[map[i, j]];
tilemap.SetTile(position, tile);
}
}
private static int[, ] PerlinNoiseCave(int[, ] map, float frequency) {
for (int i = 0; i < map.GetUpperBound(0); i++) {
for (int j = 0; j < map.GetUpperBound(1); j++) {
// Generate a new point using Perlin noise, then round it to a value of either 0 or 1
map[i, j] = Mathf.RoundToInt(Mathf.PerlinNoise(i * frequency, j * frequency));
}
}
return map;
}
}
}