Roblox Studio: Advanced Terrain Generation with Biomes

Here's an updated Lua script that incorporates multiple biomes (including snow and desert), mountains, a seed system, and performance optimizations:


-- Advanced Terrain Generation Script with Biomes

local Terrain = game.Workspace.Terrain
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- Configuration
local CHUNK_SIZE = 16
local RENDER_DISTANCE = 5
local MAX_HEIGHT = 100
local NOISE_SCALE = 0.005
local BIOME_SCALE = 0.001
local MOUNTAIN_SCALE = 0.002
local SEED = math.random(1, 1000000) -- Random seed, change as needed

-- Store generated chunks
local generatedChunks = {}

-- Biome definitions
local BIOMES = {
    PLAINS = {
        threshold = 0.3,
        baseHeight = 10,
        materials = {Enum.Material.Grass, Enum.Material.Sand, Enum.Material.Rock}
    },
    DESERT = {
        threshold = 0.6,
        baseHeight = 5,
        materials = {Enum.Material.Sand, Enum.Material.Sand, Enum.Material.Sandstone}
    },
    SNOW = {
        threshold = 0.9,
        baseHeight = 15,
        materials = {Enum.Material.Snow, Enum.Material.Snow, Enum.Material.Ice}
    },
    MOUNTAINS = {
        threshold = 1.0,
        baseHeight = 30,
        materials = {Enum.Material.Rock, Enum.Material.Rock, Enum.Material.Slate}
    }
}

-- Improved noise function with seed
local function improvedNoise(x, y, z)
    return math.noise(x + SEED, y - SEED, z + SEED)
end

-- Function to get biome based on position
local function getBiome(x, z)
    local biomeNoise = improvedNoise(x * BIOME_SCALE, 0, z * BIOME_SCALE)
    for biomeName, biomeData in pairs(BIOMES) do
        if biomeNoise <= biomeData.threshold then
            return biomeName, biomeData
        end
    end
    return "PLAINS", BIOMES.PLAINS -- Default to plains
end

-- Function to generate height using improved noise
local function getTerrainHeight(x, z)
    local biomeName, biomeData = getBiome(x, z)
    local baseHeight = biomeData.baseHeight
    local terrainNoise = improvedNoise(x * NOISE_SCALE, 0, z * NOISE_SCALE)
    local mountainNoise = improvedNoise(x * MOUNTAIN_SCALE, 0, z * MOUNTAIN_SCALE)
    
    local height = baseHeight + terrainNoise * 20
    
    if biomeName == "MOUNTAINS" then
        height = height + mountainNoise * 50
    end
    
    return math.floor(math.clamp(height, 1, MAX_HEIGHT))
end

-- Function to create terrain for a single chunk
local function createChunk(chunkX, chunkZ)
    local chunkKey = chunkX .. "," .. chunkZ
    if generatedChunks[chunkKey] then return end

    local terrainRegion = Region3.new(
        Vector3.new(chunkX * CHUNK_SIZE, 0, chunkZ * CHUNK_SIZE),
        Vector3.new((chunkX + 1) * CHUNK_SIZE - 1, MAX_HEIGHT, (chunkZ + 1) * CHUNK_SIZE - 1)
    )
    
    local materials = {}
    local occupancy = {}
    
    for x = 0, CHUNK_SIZE - 1 do
        for z = 0, CHUNK_SIZE - 1 do
            local worldX = chunkX * CHUNK_SIZE + x
            local worldZ = chunkZ * CHUNK_SIZE + z
            local height = getTerrainHeight(worldX, worldZ)
            local _, biomeData = getBiome(worldX, worldZ)
            
            for y = 0, height do
                local index = x + 1 + (z * CHUNK_SIZE) + (y * CHUNK_SIZE * CHUNK_SIZE)
                local material
                
                if y == height then
                    material = biomeData.materials[1]
                elseif y > height - 3 then
                    material = biomeData.materials[2]
                else
                    material = biomeData.materials[3]
                end
                
                materials[index] = material
                occupancy[index] = 1
            end
        end
    end
    
    Terrain:WriteVoxels(terrainRegion, CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE, materials, occupancy)
    generatedChunks[chunkKey] = true
end

-- Function to update terrain around the player
local function updateTerrain(player)
    local character = player.Character
    if not character then return end
    
    local position = character.PrimaryPart.Position
    local chunkX = math.floor(position.X / CHUNK_SIZE)
    local chunkZ = math.floor(position.Z / CHUNK_SIZE)
    
    for x = -RENDER_DISTANCE, RENDER_DISTANCE do
        for z = -RENDER_DISTANCE, RENDER_DISTANCE do
            createChunk(chunkX + x, chunkZ + z)
        end
    end
end

-- Update terrain when a player's character spawns
Players.PlayerAdded:Connect(function(player)
    player.CharacterAdded:Connect(function(character)
        wait(1)
        updateTerrain(player)
    end)
end)

-- Continuously update terrain as players move
local lastUpdate = 0
local UPDATE_INTERVAL = 0.5 -- Update every 0.5 seconds

RunService.Heartbeat:Connect(function(deltaTime)
    lastUpdate = lastUpdate + deltaTime
    if lastUpdate >= UPDATE_INTERVAL then
        for _, player in ipairs(Players:GetPlayers()) do
            updateTerrain(player)
        end
        lastUpdate = 0
    end
end)

Key Improvements and Features:

  1. Multiple Biomes: Added plains, desert, snow, and mountain biomes.
  2. Seed System: Implemented a seed-based noise generation for consistent terrain across game sessions.
  3. Mountains: Added a separate noise layer for mountain generation.
  4. Performance Optimization:
  5. Biome-specific Materials: Each biome uses appropriate materials for surface, subsurface, and deep layers.

How to Use:

  1. Copy the script using the "Copy to Clipboard" button.
  2. In Roblox Studio, insert a new Script into the Workspace.
  3. Paste the copied code into the script.
  4. Adjust the configuration variables as needed:
  5. Run the game to see the advanced terrain generation in action!

Note: While this script includes several optimizations, very large worlds or many simultaneous players may still impact performance. For production games, consider implementing additional optimizations such as multi-threading, custom mesh generation, or server-side terrain generation.