Add chunk wrapping
This commit is contained in:
parent
e255ae4e85
commit
832f9a5c9a
240
main.lua
240
main.lua
@ -1,110 +1,133 @@
|
||||
local zprite = require("zprite")
|
||||
|
||||
local tex = love.graphics.newImage("atlas.png")
|
||||
tex:setFilter("nearest", "nearest")
|
||||
|
||||
local function water_color(layer)
|
||||
local value = layer / 24
|
||||
return value / 4, value / 2, value
|
||||
end
|
||||
|
||||
local function sand_color(layer)
|
||||
return layer / 32 + 0.2, layer / 32 + 0.15, 0.4
|
||||
end
|
||||
|
||||
local function dirt_color(layer)
|
||||
if layer < 32 then
|
||||
return layer / 40 / 2.5, layer / 80 / 2.5, 0.1
|
||||
else
|
||||
return 0.05, (layer - 32) / 36 + 0.3, 0.05
|
||||
end
|
||||
end
|
||||
|
||||
local function mountain_color(layer)
|
||||
if layer < 58 then
|
||||
local value = layer / 64 / 2 - 0.1
|
||||
return value, value, value
|
||||
else
|
||||
local value = (layer - 58) / 20 + 0.7
|
||||
return value, value, value
|
||||
end
|
||||
end
|
||||
|
||||
local function pick_colorfn(maxlayer)
|
||||
if maxlayer < 16 then
|
||||
return water_color
|
||||
elseif maxlayer < 22 then
|
||||
return sand_color
|
||||
elseif maxlayer < 46 then
|
||||
return dirt_color
|
||||
else
|
||||
return mountain_color
|
||||
end
|
||||
end
|
||||
|
||||
local function ease(n)
|
||||
return 5 ^ (3.1 * (n ^ 0.3) - 3) + 1 - 1.1 ^ n
|
||||
end
|
||||
|
||||
local WATER = love.graphics.newQuad(1, 1, 8, 8, tex)
|
||||
local SAND = love.graphics.newQuad(11, 1, 8, 8, tex)
|
||||
local DIRT = love.graphics.newQuad(21, 1, 8, 8, tex)
|
||||
local GRASS = love.graphics.newQuad(31, 1, 8, 8, tex)
|
||||
local STONE = love.graphics.newQuad(1, 11, 8, 8, tex)
|
||||
local SNOW = love.graphics.newQuad(11, 11, 8, 8, tex)
|
||||
|
||||
local function dirt_sprite(layer)
|
||||
if layer < 32 then
|
||||
return DIRT
|
||||
end
|
||||
return GRASS
|
||||
end
|
||||
|
||||
local function mountain_sprite(layer)
|
||||
if layer < 58 then
|
||||
return STONE
|
||||
end
|
||||
return SNOW
|
||||
end
|
||||
|
||||
local function pick_sprite(maxlayer)
|
||||
if maxlayer < 16 then
|
||||
return WATER
|
||||
end
|
||||
if maxlayer < 22 then
|
||||
return SAND
|
||||
end
|
||||
if maxlayer < 46 then
|
||||
return dirt_sprite
|
||||
end
|
||||
return mountain_sprite
|
||||
end
|
||||
|
||||
local z = require("zprite").zchunk.new(tex, 128, 64)
|
||||
|
||||
local function update_map()
|
||||
z:clear()
|
||||
for i = -160, 160 do
|
||||
for j = -160, 160 do
|
||||
local noise_value = love.math.simplexNoise(i * 0.008, j * 0.008)
|
||||
local layers = ease(noise_value) * 64
|
||||
z:put(i * 8, j * 8, pick_sprite(layers), math.floor(layers) + 1, pick_colorfn(layers))
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
end
|
||||
local co = coroutine.create(update_map)
|
||||
|
||||
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)
|
||||
for _ = 1, 64 do
|
||||
if coroutine.status(co) == "suspended" then
|
||||
coroutine.resume(co)
|
||||
end
|
||||
end
|
||||
|
||||
if love.keyboard.isDown("d") then
|
||||
local dx = 256 * math.cos(-angle)
|
||||
local dy = 256 * math.sin(-angle)
|
||||
@ -136,17 +159,31 @@ function love.update(dt)
|
||||
angle = angle - dt
|
||||
end
|
||||
if love.keyboard.isDown("f") then
|
||||
scale = scale - dt * 5
|
||||
scale = scale * (1 - dt)
|
||||
if scale < 0.2 then
|
||||
scale = 0.2
|
||||
end
|
||||
end
|
||||
if love.keyboard.isDown("r") then
|
||||
scale = scale + dt * 5
|
||||
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()
|
||||
@ -155,10 +192,11 @@ 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, y)
|
||||
t:translate(x - z._chunk_size, y - z._chunk_size / 2)
|
||||
z:draw(t)
|
||||
end
|
||||
|
2
zprite
2
zprite
@ -1 +1 @@
|
||||
Subproject commit ccfa075d244c87171799941125decd143c3fb37a
|
||||
Subproject commit 071b00d922ba6dcf76b5ecae0fdd5c01579482bf
|
Loading…
x
Reference in New Issue
Block a user