Browse files

Chunk generation vaguely near working

  • Loading branch information...
1 parent a76474a commit f7e8469d59fd8452fabb33ce5c255a45fa667fb1 @Middlerun committed Jun 29, 2011
Showing with 244 additions and 33 deletions.
  1. +158 −1 chunk.lua
  2. +66 −29 main.lua
  3. +18 −1 perlin.lua
  4. +2 −2 terrain.lua
View
159 chunk.lua
@@ -1,12 +1,19 @@
+
+air = 0
+stone = 1
+dirt = 3
+
Chunk = {}
function Chunk:new()
o = {}
setmetatable(o, self)
self.__index = self
- o.generated = 0
+ o.generated = false
o.value = {}
+ o.value = {}
+ o.perlin = {}
for r = 1, 32 do
o.value[r] = {}
o.perlin[r] = {}
@@ -19,10 +26,160 @@ function Chunk:new()
return o
end
+function Chunk:generate(seed, chunkR, chunkC)
+ self.perlin = self:generatePerlin(seed, chunkR, chunkC)
+
+ local absR
+ local absC
+
+ self.value = {}
+ for r = 1, 32 do
+ absR = chunkR * 32 + r
+ self.value[r] = {}
+ dirtMargin = (256-absR) * 0.01
+ for c = 1, 32 do
+ absC = chunkC * 32 + c
+ value = self.perlin[r][c]
+ if r < 128 then
+ value = value + (128 - r) * 0.02
+ end
+ if value > 0.5 then self.value[r][c] = air
+ elseif value > 1.4 - dirtMargin or value < -0.6 then self.value[r][c] = dirt
+ else self.value[r][c] = stone
+ end
+ end
+ end
+ self.generated = true
+end
+
+function Chunk:generatePerlin(seed, chunkR, chunkC)
+ local persistence = 0.55
+ local N = 6
+ local amplitude = 1
+ local compInterp
+ local compAmplitude
+ local comp
+ local data = {}
+ for r = 1, 32 do
+ data[r] = {}
+ for c = 1, 32 do
+ data[r][c] = 0
+ end
+ end
+ for i = N, 1, -1 do
+ compInterp = 2^(i-1)
+ compAmplitude = amplitude * persistence^(N-i)
+ comp = self:perlinComponent2D(seed+i*1000, chunkR, chunkC, compInterp, compAmplitude)
+ for r = 1, 32 do
+ for c = 1, 32 do
+ data[r][c] = data[r][c] + comp[r][c]
+ end
+ end
+ end
+ return data
+end
+
+function Chunk:perlinComponent2D(seed, chunkR, chunkC, N, amplitude)
+
+ local topEdge1 = chunkR * 32 + 1
+ local bottomEdge1 = (chunkR + 1) * 32 + 1
+ local leftEdge1 = chunkC * 32 + 1
+ local rightEdge1 = (chunkC + 1) * 32 + 1
+
+ local topEdge2 = math.floor((topEdge1 - 1) / N) - 1
+ local bottomEdge2 = math.ceil ((bottomEdge1 - 1) / N) + 1
+ local leftEdge2 = math.floor((leftEdge1 - 1) / N) - 1
+ local rightEdge2 = math.ceil ((rightEdge1 - 1) / N) + 1
+
+ local rawData = {}
+ local finalData = {}
+ for r = leftEdge2, rightEdge2 do
+ rawData[r - leftEdge2 + 1] = {}
+ for c = topEdge2, bottomEdge2 do
+ rawData[r - leftEdge2 + 1][c - topEdge2 + 1] = amplitude * rand:get(seed + 1000*N + r, c)
+ end
+ end
+
+ local interpData = self:interpolate2D(rawData, chunkR, chunkC, N)
+ for r = 1, 32 do
+ finalData[r] = {}
+ for c = 1, 32 do
+ finalData[r][c] = interpData[r][c]
+ end
+ end
+ return finalData
+end
+
+function Chunk:interpolate2D(values, chunkR, chunkC, N)
+
+ local topEdge1 = chunkR * 32 + 1
+ local bottomEdge1 = (chunkR + 1) * 32 + 1
+ local leftEdge1 = chunkC * 32 + 1
+ local rightEdge1 = (chunkC + 1) * 32 + 1
+
+ local topEdge2 = math.floor((topEdge1 - 1) / N) - 1
+ local bottomEdge2 = math.ceil ((bottomEdge1 - 1) / N) + 1
+ local leftEdge2 = math.floor((leftEdge1 - 1) / N) - 1
+ local rightEdge2 = math.ceil ((rightEdge1 - 1) / N) + 1
+
+ local newData1 = {}
+ local min
+ local max
+ for r = 1, #values do
+ newData1[r] = {}
+ for c = 1, #values[r] - 3 do
+ P = (values[r][c+3] - values[r][c+2]) - (values[r][c] - values[r][c+1])
+ Q = (values[r][c] - values[r][c+1]) - P
+ R = (values[r][c+2] - values[r][c])
+ S = values[r][c+1]
+ min = math.max(leftEdge1 - 1, (leftEdge2 + c) * N) % N + 1
+ max = math.min(rightEdge1 - 1, (leftEdge2 + c + 1) * N) % N + N + 1
+ for j = min, max-1 do
+ x = j/N
+ table.insert(newData1[r], P*x^3 + Q*x^2 + R*x + S)
+ end
+ end
+ end
+ assert(#newData1[1] == 32, "wrong length. chunkR="..chunkR.." chunkC="..chunkC.." N="..N)
+
+ local newData2 = {}
+ for r = 1, 32 do
+ newData2[r] = {}
+ end
+ for c = 1, 32 do
+ rowCount = 0
+ for r = 1, #newData1 - 3 do
+ P = (newData1[r+3][c] - newData1[r+2][c]) - (newData1[r][c] - newData1[r+1][c])
+ Q = (newData1[r][c] - newData1[r+1][c]) - P
+ R = (newData1[r+2][c] - newData1[r][c])
+ S = newData1[r+1][c]
+ min = math.max(topEdge1 - 1, (topEdge2 + r) * N) % N + 1
+ max = math.min(bottomEdge1 - 1, (bottomEdge2 + r + 1) * N) % N + N + 1
+ for j = min, max-1 do
+ x = j/N
+ rowCount = rowCount + 1
+ newData2[rowCount][c] = P*x^3 + Q*x^2 + R*x + S
+ end
+ end
+ end
+
+ for r = 1, 32 do
+ for c = 1, 32 do
+ assert(newData2[r][c] ~= nil, "nil value, r="..r.." c="..c.." N="..N)
+ end
+ end
+
+ return newData2
+end
+
function Chunk:getValue(r, c)
return self.value[r][c]
end
function Chunk:setValue(r, c, value)
self.value[r][c] = value
end
+
+function Chunk:isGenerated()
+ return self.generated
+end
View
95 main.lua
@@ -1,4 +1,6 @@
love.filesystem.load("perlin.lua")()
+love.filesystem.load("chunk.lua")()
+love.filesystem.load("terrain.lua")()
love.filesystem.setIdentity("lovecraft")
air = 0
@@ -7,29 +9,41 @@ dirt = 3
rand = {mySeed = 1, lastN = -1}
function love.load()
- showPerlin = 0
+ showPerlin = false
- terrain = makeTerrain()
+ terrain = Terrain:new(1)
+ chunk1 = Chunk:new()
+ chunk1:generate(1, 0, 0)
+ terrain:addChunk(chunk1, 0, 0)
+ chunk2 = Chunk:new()
+ chunk2:generate(1, 0, 1)
+ terrain:addChunk(chunk2, 0, 1)
+ chunk3 = Chunk:new()
+ chunk3:generate(1, 1, 0)
+ terrain:addChunk(chunk3, 1, 0)
+ chunk4 = Chunk:new()
+ chunk4:generate(1, 1, 1)
+ terrain:addChunk(chunk4, 1, 1)
end
function love.update(dt)
end
function love.draw()
- if showPerlin == 1 then plot2D(terrain.perlin)
+ if showPerlin then drawTerrainPerlin(terrain, 4, 0, 0)
else
love.graphics.setColor(161, 235, 255, 255)
love.graphics.rectangle("fill", -1, -1, love.graphics.getWidth()+2, love.graphics.getHeight()+2)
- drawTerrain(terrain)
+ drawTerrain(terrain, 4, 0, 0)
end
end
function love.keypressed(k, u)
if k == "r" then
terrain = makeTerrain()
elseif k == "p" then
- showPerlin = 1 - showPerlin
+ showPerlin = not showPerlin
elseif k == "escape" then
love.event.push("q")
end
@@ -40,11 +54,14 @@ function love.keyreleased(k)
end
function rand:get(seed, n)
- if n <= 0 then return nil end
+ if n <= 0 then n = -2 * n
+ else n = 2 * n - 1
+ end
+
if seed ~= self.mySeed or self.lastN < 0 or n <= self.lastN then
self.mySeed = seed
math.randomseed(seed)
- self.lastN = 0
+ self.lastN = -1
end
while self.lastN < n do
num = math.random()
@@ -53,47 +70,30 @@ function rand:get(seed, n)
return num - 0.5
end
-function plot1D(values)
- love.graphics.line(0, love.graphics.getHeight()/2 - 200, love.graphics.getWidth(), love.graphics.getHeight()/2 - 200)
- love.graphics.line(0, love.graphics.getHeight()/2 + 200, love.graphics.getWidth(), love.graphics.getHeight()/2 + 200)
- for i = 1, #values - 1 do
- love.graphics.line((i-1)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i] * 400, (i)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i+1] * 400)
- end
-end
-
-function plot2D(values)
- for r = 1, #values do
- for c = 1, #(values[1]) do
- love.graphics.setColor(128 + 40 * values[r][c], 128 + 40 * values[r][c], 128 + 40 * values[r][c], 255)
- love.graphics.rectangle("fill", (c-1)/(#(values[1]))*love.graphics.getWidth(), (r-1)/(#values)*love.graphics.getHeight(), love.graphics.getWidth()/#(values[1]), love.graphics.getHeight()/#values)
- end
- end
-end
-
function makeTerrain(seed)
terrain = {}
if seed == nil then seed = os.time() end
terrain.seed = seed
- terrain.perlin = perlin2D(seed, 341, 256, 0.9, 20, 1)
+ terrain.perlin = perlin2D(seed, 341, 256, 0.55, 6, 1)
terrain.value = {}
for r = 1, #terrain.perlin do
terrain.value[r] = {}
dirtMargin = (256-r) * 0.01
for c = 1, #(terrain.perlin[r]) do
value = terrain.perlin[r][c]
if r < 128 then
- value = value + (128 - r) * 0.05
+ value = value + (128 - r) * 0.02
end
- if value > 0.9 then terrain.value[r][c] = air
- elseif value > 1.6 - dirtMargin or value < -1.4 then terrain.value[r][c] = dirt
+ if value > 0.5 then terrain.value[r][c] = air
+ elseif value > 1.4 - dirtMargin or value < -0.6 then terrain.value[r][c] = dirt
else terrain.value[r][c] = stone
end
end
end
return terrain
end
-function drawTerrain(terrain)
+function drawTerrainOld(terrain)
for r = 1, #terrain.value do
for c = 1, #(terrain.value[1]) do
if terrain.value[r][c] ~= air then
@@ -105,5 +105,42 @@ function drawTerrain(terrain)
end
end
+function drawTerrain(terrain, zoom, x, y)
+ for r = 0, 1 do
+ for c = 0, 1 do
+ drawChunk(terrain:getChunk(r, c), zoom, x-32*c, y-32*r)
+ end
+ end
+end
+
+function drawChunk(chunk, zoom, x, y)
+ for r = 1, 32 do
+ for c = 1, 32 do
+ if chunk.value[r][c] ~= air then
+ if chunk.value[r][c] == stone then love.graphics.setColor(163, 163, 163, 255) end
+ if chunk.value[r][c] == dirt then love.graphics.setColor(130, 97, 21, 255) end
+ love.graphics.rectangle("fill", (c-1-x)*zoom + love.graphics.getWidth()/2, (r-1-y)*zoom+love.graphics.getHeight()/2, zoom, zoom)
+ end
+ end
+ end
+end
+
+function drawTerrainPerlin(terrain, zoom, x, y)
+ for r = 0, 1 do
+ for c = 0, 1 do
+ drawChunkPerlin(terrain:getChunk(r, c), zoom, x-32*c, y-32*r)
+ end
+ end
+end
+
+function drawChunkPerlin(chunk, zoom, x, y)
+ for r = 1, 32 do
+ for c = 1, 32 do
+ love.graphics.setColor(128 + 80 * chunk.perlin[r][c], 128 + 80 * chunk.perlin[r][c], 128 + 80 * chunk.perlin[r][c], 255)
+ love.graphics.rectangle("fill", (c-1-x)*zoom + love.graphics.getWidth()/2, (r-1-y)*zoom+love.graphics.getHeight()/2, zoom, zoom)
+ end
+ end
+end
+
View
19 perlin.lua
@@ -111,7 +111,7 @@ function perlin2D(seed, width, height, persistence, N, amplitude)
for i = N, 1, -1 do
compInterp = 2^(i-1)
compAmplitude = amplitude * persistence^(N-i)
- comp = perlinComponent2D(seed+i*1000, width, height, i, compAmplitude)
+ comp = perlinComponent2D(seed+i*1000, width, height, compInterp, compAmplitude)
for r = 1, height do
for c = 1, width do
data[r][c] = data[r][c] + comp[r][c]
@@ -121,3 +121,20 @@ function perlin2D(seed, width, height, persistence, N, amplitude)
return data
end
+function plot1D(values)
+ love.graphics.line(0, love.graphics.getHeight()/2 - 200, love.graphics.getWidth(), love.graphics.getHeight()/2 - 200)
+ love.graphics.line(0, love.graphics.getHeight()/2 + 200, love.graphics.getWidth(), love.graphics.getHeight()/2 + 200)
+ for i = 1, #values - 1 do
+ love.graphics.line((i-1)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i] * 400, (i)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i+1] * 400)
+ end
+end
+
+function plot2D(values)
+ for r = 1, #values do
+ for c = 1, #(values[1]) do
+ love.graphics.setColor(128 + 80 * values[r][c], 128 + 80 * values[r][c], 128 + 80 * values[r][c], 255)
+ love.graphics.rectangle("fill", (c-1)/(#(values[1]))*love.graphics.getWidth(), (r-1)/(#values)*love.graphics.getHeight(), love.graphics.getWidth()/#(values[1]), love.graphics.getHeight()/#values)
+ end
+ end
+end
+
View
4 terrain.lua
@@ -12,8 +12,8 @@ function Terrain:new(seed)
return o
end
-function Terrain:addChunk(r, c, chunk)
- if self.chunk[r] == nil do self.chunk[r] = {}
+function Terrain:addChunk(chunk, r, c)
+ if self.chunk[r] == nil then self.chunk[r] = {} end
self.chunk[r][c] = chunk
end

0 comments on commit f7e8469

Please sign in to comment.