Explorinator9000/main.lua
2025-07-19 11:02:18 -04:00

203 lines
4.3 KiB
Lua

local zprite = require("zprite")
local tex = love.graphics.newImage("atlas.png")
tex:setFilter("nearest", "nearest")
local x = 0
local y = 0
local angle = 0
local scale = 1
local dist = 4
local atlas = {
water = love.graphics.newQuad(1, 1, 8, 8, tex),
sand = love.graphics.newQuad(11, 1, 8, 8, tex),
dirt = love.graphics.newQuad(21, 1, 8, 8, tex),
grass = love.graphics.newQuad(31, 1, 8, 8, tex),
stone = love.graphics.newQuad(1, 11, 8, 8, tex),
snow = love.graphics.newQuad(11, 11, 8, 8, tex),
}
local colors = {}
function colors.water(layer)
return 0.1, layer / 16, layer / 8
end
function colors.sand(layer)
return layer / 16 + 0.2, layer / 16 + 0.15, 0.4
end
function colors.dirt(layer)
if layer < 20 then
return layer / 40, layer / 80, 0.1
else
return 0.1, layer / 32 + 0.3, 0.1
end
end
function colors.stone(layer)
local value = layer / 48 - 0.2
return value / 1.1, value, value * 1.1
end
function colors.snow(layer)
local value = layer / 48 + 0.2
return value / 1.1, value, value * 1.1
end
local z = zprite.zchunk.new(tex, 16 * 8, 32, dist * 2 + 1)
local function layered_noise(x, y, layers, persistence)
local freq = 1
local ampl = 1
local maxval = 0
local val = 0
for i = 1, layers do
val = val + love.math.perlinNoise(x * freq, y * freq) * ampl
maxval = maxval + ampl
ampl = ampl * persistence
freq = freq * 2
end
return val / maxval
end
local function heightmap(x, y)
return layered_noise(x * 0.003, y * 0.003, 1, 0.1)
end
local function dirtgrass_sprite(layer)
if layer < 20 then
return atlas.dirt
end
return atlas.grass
end
local function pick_from_atlas(height)
if height < 0.2 then
return atlas.water
end
if height < 0.3 then
return atlas.sand
end
if height < 0.7 then
return dirtgrass_sprite
end
if height < 0.9 then
return atlas.stone
end
return atlas.snow
end
local function pick_color(height)
if height < 0.25 then
return colors.water
end
if height < 0.3 then
return colors.sand
end
if height < 0.7 then
return colors.dirt
end
if height < 0.9 then
return colors.stone
end
return colors.snow
end
local function generate(x, y)
local height = heightmap(x, y)
z:put(x, y, pick_from_atlas(height), math.ceil(height * 32), pick_color(height))
end
local generated = {}
local function generate_chunk(cx, cy)
local idx = z:_chunk_index(cx * z._chunk_size, cy * z._chunk_size)
if generated[idx] then
return
end
generated[idx] = { cx, cy }
z:clear(cx * z._chunk_size, cy * z._chunk_size)
for i = 1, z._chunk_size, 8 do
for j = 1, z._chunk_size, 8 do
local x = cx * z._chunk_size + i - 1
local y = cy * z._chunk_size + j - 1
generate(x, y)
end
end
end
function love.update(dt)
if love.keyboard.isDown("d") then
local dx = 256 * math.cos(-angle)
local dy = 256 * math.sin(-angle)
x = x - dx * dt
y = y - dy * dt
end
if love.keyboard.isDown("a") then
local dx = 256 * math.cos(-angle)
local dy = 256 * math.sin(-angle)
x = x + dx * dt
y = y + dy * dt
end
if love.keyboard.isDown("s") then
local dx = 256 * math.cos(-angle + math.pi / 2)
local dy = 256 * math.sin(-angle + math.pi / 2)
x = x - dx * dt
y = y - dy * dt
end
if love.keyboard.isDown("w") then
local dx = 256 * math.cos(-angle + math.pi / 2)
local dy = 256 * math.sin(-angle + math.pi / 2)
x = x + dx * dt
y = y + dy * dt
end
if love.keyboard.isDown("q") then
angle = angle + dt
end
if love.keyboard.isDown("e") then
angle = angle - dt
end
if love.keyboard.isDown("f") then
scale = scale * (1 - dt)
if scale < 0.2 then
scale = 0.2
end
end
if love.keyboard.isDown("r") then
scale = scale * (1 + dt)
if scale > 5 then
scale = 5
end
end
local center_cx = -math.floor(x / z._chunk_size)
local center_cy = -math.floor(y / z._chunk_size)
for key, gen in pairs(generated) do
if math.abs(gen[1] - center_cx) > dist or math.abs(gen[2] - center_cy) > dist then
generated[key] = nil
end
end
for cx = center_cx - dist, center_cx + dist do
for cy = center_cy - dist, center_cy + dist do
generate_chunk(cx, cy)
end
end
end
local t = love.math.newTransform()
function love.draw()
for _, chunk in pairs(z._chunks) do
chunk.z._height_scale = 12 * scale
end
t:reset()
t:translate(love.graphics.getWidth() / 2, love.graphics.getHeight() / 2)
t:scale(scale, scale)
t:rotate(angle)
t:translate(x - z._chunk_size, y - z._chunk_size / 2)
z:draw(t)
end