-
-
Save zombrodo/6073542191b7ebbc2d2cadfc25934a98 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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