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) enter image description here

The problems with this method:

  1. 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?
  2. 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)?
  3. 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;
  • 1
    \$\begingroup\$ Are you dead-set on using Voroni diagrams for this? Because I would do this with Perlin Noise and control the ratio of grass to soil by picking the cutoff value between one and the other. But I don't want to claim that this isn't possible to do with Voroni diagrams. I don't have enough experience with them to judge that. \$\endgroup\$
    – Philipp
    Mar 27 '20 at 11:22
  • \$\begingroup\$ Well I've tried with Perlin Noise but there were 2 problems: 1. The generated maps were not of islands but more of single tiles as I said. 2. I didn't manage to add random element to the map generation. So I've switched to Voronoi. So far it's better, but not perfect yet. \$\endgroup\$
    – lihail
    Mar 27 '20 at 11:29
  • \$\begingroup\$ It sounds like you were using a mix of frequencies of noise too high for your needs. Bringing this down to fewer, bigger, blobbier islands should be just a matter of tuning your noise parameters. Adding an offset or re-shuffling your permutation table can add randomization. I'd second Philipp that noise looks like what you want, and you should consider editing your question to show your problems with using noise so we can help you solve them. \$\endgroup\$
    – DMGregory
    Mar 27 '20 at 11:37
  • \$\begingroup\$ But if you want help with your voronoi implementation, you should show us your code. It looks like you still have a bug in the code that determines the nearest cell, leading to those diagonal artifacts. \$\endgroup\$
    – DMGregory
    Mar 27 '20 at 12:11
  • \$\begingroup\$ Maybe. Added the code. \$\endgroup\$
    – lihail
    Mar 27 '20 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.