Skip to content

Instantly share code, notes, and snippets.

@zombrodo
Created November 10, 2023 13:33
Show Gist options
  • Save zombrodo/6073542191b7ebbc2d2cadfc25934a98 to your computer and use it in GitHub Desktop.
Save zombrodo/6073542191b7ebbc2d2cadfc25934a98 to your computer and use it in GitHub Desktop.
local CHUNK_SIZE = 32
-- ==============================================
-- World Generation
-- ==============================================
local XL = 17
local LG = 9
local MD = 7
local SM = 5
local XS = 3
local function getIslandBudget()
local budget = { XL }
for i = 1, 5 do
table.insert(budget, LG)
end
for i = 1, 6 do
table.insert(budget, MD)
end
for i = 1, 4 do
table.insert(budget, SM)
end
for i = 1, 6 do
table.insert(budget, XS)
end
return budget
end
local octaves = 8
local persistence = 0.5
local scale = 0.01
local function generateNoise(x, y)
local sum = 0
local amplitude = 1
local frequency = scale
local noise = 0
for i = 1, octaves do
noise = noise + love.math.noise(x * frequency, y * frequency) * amplitude
sum = sum + amplitude
amplitude = amplitude * persistence
frequency = frequency * 2
end
return noise / sum
end
-- ==============================================
-- Physics
-- ==============================================
local world
local function physicsObject(x, y, chunkSize)
local size = chunkSize * CHUNK_SIZE
local body = love.physics.newBody(world, x, y, "dynamic")
local shape = love.physics.newRectangleShape(size, size)
local fixture = love.physics.newFixture(body, shape)
body:setFixedRotation(true)
return {
body = body,
shape = shape,
fixture = fixture,
chunkSize = chunkSize,
size = size
}
end
-- ===============================================
-- Where we put it all together
-- ===============================================
local physicsObjects = {}
local function generate()
local islands = getIslandBudget()
for i, island in ipairs(islands) do
local physObj = physicsObject(
(love.graphics.getWidth() / 2) + love.math.random(-16, 16),
(love.graphics.getHeight() / 2) + love.math.random(-16, 16),
island
)
table.insert(physicsObjects, physObj)
end
end
local islandHeightMaps = {}
local function distance(x1, y1, x2, y2)
local dx = x2 - x1
local dy = y2 - y1
return math.sqrt(dx * dx + dy * dy)
end
local function generateHeightMaps()
for i, physObj in ipairs(physicsObjects) do
local size = physObj.size
local result = {}
local xOffset = love.math.random(-1024, 1024)
local yOffset = love.math.random(-1024, 1024)
for y = 0, size do
if not result[y] then
result[y] = {}
end
for x = 0, size do
local noise = generateNoise(x + xOffset, y + yOffset)
local dist = distance(size / 2, size / 2, x, y) / (size / 2)
result[y][x] = noise * (1 - dist)
end
end
table.insert(islandHeightMaps, result)
end
end
-- ==============================================
-- Love functions
-- ==============================================
function love.load()
world = love.physics.newWorld(0, 0)
generate() -- see below
end
local sleeping = false
local function allSleeping(bodies)
for i, body in ipairs(bodies) do
if body:isAwake() then
return false
end
end
return true
end
local function round(n)
-- Kinda wild that lua doesn't have math.round
return math.floor(n + 0.5)
end
function love.update(dt)
if not sleeping then
world:update(dt)
end
if allSleeping(world:getBodies()) then
sleeping = true
for i, body in ipairs(world:getBodies()) do
local bx, by = body:getPosition()
body:setPosition(
round(bx / CHUNK_SIZE) * CHUNK_SIZE,
round(by / CHUNK_SIZE) * CHUNK_SIZE
)
end
generateHeightMaps()
end
end
local colours = {
{ 0.2, 0.46, 0.08, 1 }, -- grass
{ 0.14, 0.28, 0.53 }, -- shallow water
{ 0.25, 0.39, 0.65, 1 }, -- beach
{ 0.96, 0.95, 0.65, 1 }, -- deep water
}
local function determineColour(height)
if height <= 0.20 then
return colours[2]
elseif height > 0.2 and height <= 0.3 then
return colours[3]
elseif height > 0.3 and height < 0.33 then
return colours[4]
else
return colours[1]
end
end
function love.draw()
love.graphics.clear(colours[2])
for i, physObj in ipairs(physicsObjects) do
local bx, by = physObj.body:getPosition()
local x = bx - physObj.size / 2
local y = by - physObj.size / 2
if not sleeping then
love.graphics.setColor(
physObj.chunkSize / XL,
(physObj.chunkSize / XL) / 2,
physObj.chunkSize / XL
)
love.graphics.rectangle(
"fill", x, y, physObj.size, physObj.size
)
else
local heightMap = islandHeightMaps[i]
for hy = 0, physObj.size do
for hx = 0, physObj.size do
local height = heightMap[hy][hx]
love.graphics.setColor(determineColour(height))
love.graphics.points(hx + x, hy + y)
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment