This script will generate a basic island using terrain for you, with easy configuration to help you create a basic starting place for any terrain based map. This script isnt going to give you a state of the art map and is in no way as detailed as it could be but it does give you a quick and easy way to get started.
Example generations:
The code:
-- SERVICES
local TERRAIN = workspace.Terrain
-- ## CONFIGURATION
-- GENERATION OFFSET (Change these to place a new island without deleting old ones)
local OFFSET_X = 0
local OFFSET_Z = 0
-- MAP SIZE (Must be a multiple of 4, 1024 XZ is maximum)
local MAP_SIZE_XZ = 1024
local MAP_MAX_HEIGHT = 256
-- SEED (Set a specific number for the same island every time, or leave random)
local SEED = math.random(1, 100000)
-- WATER & SHORE
local WATER_LEVEL = 64 -- The height of the water in studs.
local SAND_BEACH_HEIGHT = 4 -- How many studs high the sand beaches are above the water.
local WATER_BORDER_WIDTH = 32 -- How wide the water channel around the map edge should be.
local SHORE_WIDTH = 150 -- The width of the shores for a gentle slope.
-- ISLAND SHAPE & BASE
local ISLAND_ROUNDNESS = 4 -- Controls the island shape. 2 is a perfect circle, higher numbers are more square.
local ISLAND_BASE_HEIGHT = 70 -- The base height of the flat parts of the island.
-- HILL GENERATION
local HILL_DENSITY = 0.4 -- How much of the island is hilly (0 = all flat, 1 = all rugged).
local HILL_MASK_SCALE = 450 -- The size of the hilly/flat regions. Larger = bigger patches.
local NOISE_SCALE = 80 -- The size of the individual hills within the rugged patches.
local NOISE_AMPLITUDE = 250 -- How high the hills are.
-- COASTLINE DETAILING
local COASTLINE_NOISE_SCALE = 90 -- The size of the coastal features.
local COASTLINE_NOISE_INTENSITY = 25 -- How much the noise affects the coast.
-- ## GENERATION LOGIC
print(string.format("Starting new island generation at offset (%d, %d) with seed: %d", OFFSET_X, OFFSET_Z, SEED))
local RESOLUTION = 4
local resX, resY, resZ = MAP_SIZE_XZ / RESOLUTION, MAP_MAX_HEIGHT / RESOLUTION, MAP_SIZE_XZ / RESOLUTION
local materials, occupancies = {}, {}
for x = 1, resX do
materials[x], occupancies[x] = {}, {}
for y = 1, resY do
materials[x][y], occupancies[x][y] = {}, {}
end
end
local islandCenterX = (MAP_SIZE_XZ / 2) + OFFSET_X
local islandCenterZ = (MAP_SIZE_XZ / 2) + OFFSET_Z
local outerRadius = (MAP_SIZE_XZ / 2) - WATER_BORDER_WIDTH
local plateauRadius = outerRadius - SHORE_WIDTH
for x = 1, resX do
for z = 1, resZ do
-- Apply the offset to get the correct world coordinates
local worldX, worldZ = (x * RESOLUTION) + OFFSET_X, (z * RESOLUTION) + OFFSET_Z
local dx = math.abs(worldX - islandCenterX)
local dz = math.abs(worldZ - islandCenterZ)
local baseDist = (dx^ISLAND_ROUNDNESS + dz^ISLAND_ROUNDNESS)^(1/ISLAND_ROUNDNESS)
local coastlineNoiseX = worldX / COASTLINE_NOISE_SCALE + SEED
local coastlineNoiseZ = worldZ / COASTLINE_NOISE_SCALE + SEED
local coastlineNoise = math.noise(coastlineNoiseX, coastlineNoiseZ) * COASTLINE_NOISE_INTENSITY
local finalDist = baseDist - coastlineNoise
local shore_alpha = math.clamp((finalDist - plateauRadius) / SHORE_WIDTH, 0, 1)
local falloff = 1 - shore_alpha
local baseIslandHeight = ISLAND_BASE_HEIGHT * falloff
local hillMaskNoiseX = worldX / HILL_MASK_SCALE + (SEED * 2)
local hillMaskNoiseZ = worldZ / HILL_MASK_SCALE + (SEED * 2)
local hillMask = (math.noise(hillMaskNoiseX, hillMaskNoiseZ) + 1) / 2
local hillHeight = 0
if hillMask > (1 - HILL_DENSITY) then
local terrainNoiseCoordX, terrainNoiseCoordZ = (worldX / NOISE_SCALE) + SEED, (worldZ / NOISE_SCALE) + SEED
local terrainNoise = (math.noise(terrainNoiseCoordX, terrainNoiseCoordZ) + 1) / 2
local hillIntensity = math.clamp((hillMask - (1 - HILL_DENSITY)) / HILL_DENSITY, 0, 1)
hillHeight = terrainNoise * NOISE_AMPLITUDE * falloff * hillIntensity
end
local finalHeight = baseIslandHeight + hillHeight
for y = 1, resY do
local worldY = y * RESOLUTION
local material, occupancy = Enum.Material.Air, 0
if worldY <= finalHeight then
occupancy = 1
local depth = finalHeight - worldY
if finalHeight > WATER_LEVEL and finalHeight < WATER_LEVEL + SAND_BEACH_HEIGHT then
material = Enum.Material.Sand
elseif finalHeight > WATER_LEVEL and depth < 8 then
material = Enum.Material.Grass
elseif finalHeight > WATER_LEVEL - 5 and depth < 40 then
material = Enum.Material.Ground
else
material = Enum.Material.Rock
end
elseif worldY <= WATER_LEVEL then
occupancy = 1
material = Enum.Material.Water
end
materials[x][y][z] = material
occupancies[x][y][z] = occupancy
end
end
if x % math.floor(resX / 20) == 0 then
print(string.format("Generating data... %.0f%%", (x / resX) * 100))
end
end
print("Writing voxels...")
-- Define the generation region using the offset
local regionStart = Vector3.new(OFFSET_X, 0, OFFSET_Z)
local regionSize = Vector3.new(MAP_SIZE_XZ, MAP_MAX_HEIGHT, MAP_SIZE_XZ)
local region = Region3.new(regionStart, regionStart + regionSize)
TERRAIN:WriteVoxels(region, RESOLUTION, materials, occupancies)
print("New island generated successfully!")
General info:
The max size is X+Z of 2048, so the 1024 it is currently set to is the maximum, though you can simply change the offset by at least the size of your island (in the default case, 1024) to generate another next to it, select that new terrain and move it with the terrain tools to combine the islands as can be seen here:
The code is intended to be run in the command bar, simply copy and paste the script into there and press enter, ctrl z will undo the generation, allowing you to retry until you get a seed you like.








