Written by Natesh Narain
on
on
Procedural 2D Maps with Lua scripts
Recently adding Lua scripting to my mapgen
tool. Which allows the generation logic to be moved outside of the main program.
In this project I am using LuaJIT
and luabind
.
Here’s what a map generator script might look like:
LAYERS = "Land Elevation Moisture Temperature Biomes Final"
LAND = 0
ELEVATION = 1
MOISTURE = 2
TEMPERATURE = 3
BIOMES = 4
FINAL = 5
Tundra = 0
BorealForest = 1
BorealBarren = 2
TemperatelForest = 3
Savanna = 4
GrassLand = 5
Desert = 6
Rainforest = 7
function generate(layers, params)
landMaskNoise = params:getNoise("land_mask")
elevationNoise = params:getNoise("elevation")
moistureNoise = params:getNoise("moisture")
temperatureNoise = params:getNoise("temperature")
seaLevel = params:getFloat("sea_level")
landDark = params:getColor("land_dark")
landLight = params:getColor("land_light")
waterLight = params:getColor("water_light")
waterDark = params:getColor("water_dark")
cold = params:getColor("cold")
hot = params:getColor("hot")
t1 = params:getFloat("t1")
t2 = params:getFloat("t2")
t3 = params:getFloat("t3")
m1 = params:getFloat("m1")
m2 = params:getFloat("m2")
m3 = params:getFloat("m3")
for x=layers:startX(), layers:endX()-1, 1 do
for y=layers:startY(), layers:endY()-1, 1 do
landMask = landMaskNoise:sample(x, y)
cl = nil
ce = nil
cm = nil
ct = nil
cb = nil
cf = nil
if landMask > seaLevel then
cl = Color.from(landDark, landLight, landMask)
elevation = utils.range(elevationNoise:sample(x, y), -1, 1, 0, 1)
ce = Color.from(Color(0), Color(1), elevation)
moisture = utils.range(moistureNoise:sample(x, y), -1, 1, 0, 1)
cm = Color.from(waterLight, waterDark, moisture)
temperature = utils.range(temperatureNoise:sample(x, y), -1, 1, 0, 1) * 2.0
ct = Color.from(cold, hot, temperature / 2.0)
biome = getBiome(temperature, moisture, t1, t2, t3, m1, m2, m3)
cb = biomeToColor(biome, params)
cf = Color.from(cb, landDark, elevation)
else
cl = Color.from(waterLight, waterDark, 1.0 - landMask)
ce = Color(1)
cm = Color(1)
ct = Color(1)
cb = Color(1)
cf = cl
end
layers:set(LAND, x, y, cl)
layers:set(ELEVATION, x, y, ce)
layers:set(MOISTURE, x, y, cm)
layers:set(TEMPERATURE, x, y, ct)
layers:set(BIOMES, x, y, cb)
layers:set(FINAL, x, y, cf)
end
end
end
function getBiome(t, m, t1, t2, t3, m1, m2, m3)
if t >= t1 then
if m >= m1 then
return Rainforest
elseif m >= m2 then
return TemperatelForest
elseif m >= m3 then
return GrassLand
else
return Desert
end
elseif t >= t2 then
if m >= m1 then
return TemperatelForest
elseif m >= m2 then
return GrassLand
elseif m >= m3 then
return GrassLand
else
return Desert
end
elseif t >= t3 then
if m >= m2 then
return BorealForest
else
return BorealBarren
end
else
return Tundra
end
end
function biomeToColor(biome, params)
if biome == Rainforest then
return params:getColor("rainforest")
elseif biome == TemperatelForest then
return params:getColor("temperate")
elseif biome == GrassLand then
return params:getColor("grassland")
elseif biome == Desert then
return params:getColor("desert")
elseif biome == BorealForest then
return params:getColor("boreal")
elseif biome == BorealBarren then
return params:getColor("boreal_barren")
else
return params:getColor("tundra")
end
end
Though at the moment this is poorly optimized. Every loop new Color
objects are dynamically allocated and this is slowing the generator down considerably.