Use Noise To Generate Terrain

This tutorial assumes you're familiar with lua and roblox's API

by robro786

Author Avatar

What is noise?

This tutorial will reference the word 'noise' a lot. Although for some it may seem obvious, the noise I'm referring to is a method of smoothly interpolating pseudo-random numbers.

What the heck does that mean? Well, interpolate means to smoothly transition. In the context of noise, this means we're going to get terrain that is "smooth", as opposed to random spikes all over the place.

Pseudo random means random enough to be called random (although if you knew the formula, you could predict what values could be returned, but that's out of the scope of this tutorial).

How does noise work in code?

Noise in lua takes 3 parameters, an X, a Y, and a Z. The 'Z' argument is optional, although we'll most games use it as a 'seed' This will then return a smoothly interpolated value.

Now, roblox tells you noise returns a value between -.5 and .5, but they're lying. Sometimes Robloxscrews up, and gives a value above or below that. Why? I don't know. It's just important to remember that when coding.

What does noise have to do with terrain?

If you're familiar with minecraft, then you'll know minecraft worlds are nearly infinite. How did the developers make infinite worlds? They sure as heck didn't build each one by hand, did they? Of course not. Instead, they used noise to generate height maps and biome maps to make seemingly random terrain with variation in every seed.

How to use noise:

The basic idea to implement noise to generate terrain is this: we have a range of x and y positions, and we have a nested loop, (a loop inside another loop) that increments these x and y values by a certain offset value. Then we plug these x and y values into a noise function, and we set that value to the height of the heightmap at that x and y position.

Here's what that looks like in code: (just ignore the semi-colons; lua doesn't requre them but it's a habit of mine that I don't feel like breaking) (also, since there I can't copy and paste from an external text document into this custom text editor, there may be a few typos, please excuse them :) )

local seed = math.random(-200, 200);
local biomeIncrement = .07;
local heightScale = 10;
local width = 100;
local length = 100;
local partSize = 2;
local bottomColor = Color3.fromRGB(70, 62, 49);
local topColor = Color3.fromRGB(12, 95, 12);

local camera = game.Workspace.CurrentCamera;
camera.CFrame = CFrame.new(Vector3.new(-width * partSize/3, partSize * width/2, -length * partSize/3), Vector3.new());
camera.Focus = CFrame.new();

local partTemplate = Instance.new("Part");
partTemplate.Anchored = true;
partTemplate.CanCollide = false;
partTemplate.TopSurface = Enum.SurfaceType.Smooth;

local function clamp(val, min, max)
    if val < min then
        return min;
    elseif val > max then
        return max;
    end
    return val;
end

local function genTerrain()
    local folder = game.Workspace:FindFirstChild("Folder");
    if folder then
        folder:Destroy();
    end
    folder = Instance.new("Model", game.Workspace);
    folder.Name = "Folder"

    local xOff = 0;
    local yOff = 0;

    for x = 1, width do
        xOff = 0;
        for y = 1, length do
            local noiseValue = clamp(math.noise(xOff, yOff, seed);
            local part = partTemplate:Clone();
            part.Parent = folder;
            part.CFrame = CFrame.new(x*partSize, (noiseValue * heightScale) - heightScale/2, y * partSize);
            part.Name = noiseValue;
            part.Color = bottomColor:Lerp(topColor, noiseValue + .5);
            part.Size = Vector3.new(partSize, heightScale, partSize);

            yOff = yOff + biomeIncrement;
        end
        xOff = xOff + biomeIncrement;
    end
end

genTerrain();

The final product:

img|80x45

if the biome noise value is set to .5:

img|80x45

View in-game to comment, award, and more!