This is my first post in stack overflow, and I have no clue whether I can post stuff about roblox development here.
But anyways, here I go. I'm making a top-down pixel art survival game, and am procedurally generating "flat" worlds with many different biomes. The code is working fine, it's just that the results look really unnatural, and I don't know what to do about it.
Some examples of what I mean: world 1, world 2, world 3
Here is my code:
local biomeInfo = require(script.BiomeInfo)
local heightSeed = math.random(-2147483640, 2147483640)
local moistureSeed = math.random(-2147483640, 2147483640)
local heatSeed = math.random(-2147483640, 2147483640)
local mapSize = 250
local resolution = 20
local frequency = 15
local amplitude = 95
-- Generate noise maps
local grid = {}
for x = 1, mapSize do
grid[x] = {}
for z = 1, mapSize do
local heightMap = math.noise(x / resolution * frequency / amplitude, z / resolution * frequency / amplitude, heightSeed)
local moistureMap = math.noise(x / resolution * frequency / amplitude, z / resolution * frequency / amplitude, moistureSeed)
local heatMap = math.noise(x / resolution * frequency / amplitude, z / resolution * frequency / amplitude, heatSeed)
--[[local heightMap = math.noise(x / resolution * 1.2 / 3.2, z / resolution * 1.2 / 3.2, heightSeed)
local moistureMap = math.noise(x / resolution * 4 / 5.6, z / resolution * 4 / 5.6, moistureSeed)
local heatMap = math.noise(x / resolution * 2.7 / 7, z / resolution * 2.7 / 7, heatSeed)]]
grid[x][z] = {
["Height"] = math.clamp(heightMap, -0.5, 0.5) + 0.5,
["Moisture"] = math.clamp(moistureMap, -0.5, 0.5) + 0.5,
["Heat"] = math.clamp(heatMap, -0.5, 0.5) + 0.5,
}
end
end
-- Generate blocks
for x = 1, mapSize do
for z = 1, mapSize do
-- Get all available biomes for this block
local availableBiomes = {}
for name, value in pairs(biomeInfo) do
local condition = grid[x][z]["Height"] >= biomeInfo[name]["Height"] and grid[x][z]["Moisture"] >= biomeInfo[name]["Moisture"] and grid[x][z]["Heat"] >= biomeInfo[name]["Heat"]
if condition and not availableBiomes[name] then
table.insert(availableBiomes, name)
end
end
-- Calculate value differences for all available biomes for this block
local valueDiffs = {}
for _, biome in pairs(availableBiomes) do
valueDiffs[biome] = (grid[x][z]["Height"] - biomeInfo[biome]["Height"]) + (grid[x][z]["Moisture"] - biomeInfo[biome]["Moisture"]) + (grid[x][z]["Heat"] - biomeInfo[biome]["Heat"])
end
-- Get the lowest value difference, assign the corresponding biome
local lowestValue = 1
local selectedBiome
for biome, value in pairs(valueDiffs) do
if value < lowestValue then
lowestValue = value
selectedBiome = biome
end
end
-- Generate the block
local block = Instance.new("Part")
block.Anchored = true
block.Size = Vector3.new(8, 8, 8)
block.Position = Vector3.new(x * 8, 0, z * 8)
block.Parent = game.Workspace.World
if grid[x][z]["Height"] <= 0.2 then -- Water level
block.BrickColor = BrickColor.new("Electric blue")
elseif selectedBiome == "Grasslands" then
block.BrickColor = BrickColor.new("Bright green")
elseif selectedBiome == "Taiga" then
block.BrickColor = BrickColor.new("Baby blue")
elseif selectedBiome == "Desert" then
block.BrickColor = BrickColor.new("Cool yellow")
elseif selectedBiome == "Swamp" then
block.BrickColor = BrickColor.new("Slime green")
elseif selectedBiome == "Mountains" then
block.BrickColor = BrickColor.new("Dark stone grey")
elseif selectedBiome == "Jungle" then
block.BrickColor = BrickColor.new("Earth green")
elseif selectedBiome == "Snowy tundra" then
block.BrickColor = BrickColor.new("White")
else
block.BrickColor = BrickColor.new("Bright green")
end
block.Position = Vector3.new(x * 8, 4.5, z * 8)
block.Parent = game.Workspace.World
end
game:GetService("RunService").Heartbeat:Wait()
end
Note: I'm aware that the many elseif statements is inefficient, this is temporary, please ignore it.
The "BiomeInfo" module script:
return {
["Grasslands"] = {
["Height"] = 0.27,
["Moisture"] = 0.21,
["Heat"] = 0.25
},
["Desert"] = {
["Height"] = 0.15,
["Moisture"] = 0.05,
["Heat"] = 0.49
},
["Taiga"] = {
["Height"] = 0.28,
["Moisture"] = 0.16,
["Heat"] = 0.12
},
["Swamp"] = {
["Height"] = 0.16,
["Moisture"] = 0.44,
["Heat"] = 0.14
},
["Mountains"] = {
["Height"] = 0.43,
["Moisture"] = 0.08,
["Heat"] = 0.11
},
["Jungle"] = {
["Height"] = 0.22,
["Moisture"] = 0.51,
["Heat"] = 0.31
},
["Snowy tundra"] = {
["Height"] = 0.17,
["Moisture"] = 0.12,
["Heat"] = 0.03
},
}
This is my first time working with procedural generation, so I'm not sure if I'm applying the most efficient methods for everything.