Skip to content

Commit

Permalink
Terrain is now generated as needed in a separate thread
Browse files Browse the repository at this point in the history
  • Loading branch information
Middlerun committed Aug 15, 2011
1 parent 2f4bb06 commit 4219d7c
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 77 deletions.
35 changes: 35 additions & 0 deletions TSerial.lua
@@ -0,0 +1,35 @@
-- TSerial v1.2, a simple table serializer which turns tables into Lua script
-- by Taehl (SelfMadeSpirit@gmail.com)

-- Usage: table = TSerial.unpack( TSerial.pack(table) )
TSerial = {}
function TSerial.pack(t)
assert(type(t) == "table", "Can only TSerial.pack tables.")
if not t then return nil end
local s = "{"
for k, v in pairs(t) do
local tk, tv = type(k), type(v)
if tk == "boolean" then k = k and "[true]" or "[false]"
elseif tk == "number" then k = "["..k.."]"
elseif tk == "string" then -- no transform needed
elseif tk == "table" then k = "["..TSerial.pack(k).."]"
else error("Attempted to Tserialize a table with an invalid key: "..tostring(k))
end
if tv == "boolean" then v = v and "true" or "false"
elseif tv == "number" then -- no transform needed
elseif tv == "string" then v = string.format("%q", v)
elseif tv == "table" then v = TSerial.pack(v)
else error("Attempted to Tserialize a table with an invalid value: "..tostring(v))
end
s = s..k.."="..v..","
end
return s.."}"
end

function TSerial.unpack(s)
assert(type(s) == "string", "Can only TSerial.unpack strings.")
loadstring("TSerial.table="..s)()
local t = TSerial.table
TSerial.table = nil
return t
end
33 changes: 19 additions & 14 deletions chunk.lua
@@ -1,4 +1,3 @@

Chunk = {} Chunk = {}


function Chunk:new() function Chunk:new()
Expand All @@ -7,6 +6,8 @@ function Chunk:new()
self.__index = self self.__index = self


o.generated = false o.generated = false
o.r = nil
o.c = nil
o.block = {} o.block = {}
o.perlin = {} o.perlin = {}
o.coalNoise = {} o.coalNoise = {}
Expand All @@ -15,14 +16,10 @@ function Chunk:new()
o.perlin[r] = {} o.perlin[r] = {}
o.coalNoise[r] = {} o.coalNoise[r] = {}
for c = 1, 32 do for c = 1, 32 do
o.block[r][c] = 0 o.block[r][c] = 255
o.perlin[r][c] = 0 o.perlin[r][c] = 0
end end
end end
o.framebuffer = love.graphics.newFramebuffer(512, 512)
o.framebuffer:setFilter("linear", "nearest")
o.framebufferPerlin = love.graphics.newFramebuffer(512, 512)
o.framebufferPerlin:setFilter("linear", "nearest")


return o return o
end end
Expand All @@ -45,17 +42,17 @@ function Chunk:generate(seed, chunkR, chunkC)
value = value - absR * 0.02 value = value - absR * 0.02
end end


if value > 0.5 then self.block[r][c] = air if value > 0.5 then self.block[r][c] = AIR
elseif value > 1.4 - dirtMargin or value < -0.6 then self.block[r][c] = dirt elseif value > 1.4 - dirtMargin or value < -0.6 then self.block[r][c] = DIRT
else self.block[r][c] = stone else self.block[r][c] = STONE
end end


if self.block[r][c] == stone and self.coalNoise[r][c] > 0.08 then self.block[r][c] = coalOre end if self.block[r][c] == STONE and self.coalNoise[r][c] > 0.08 then self.block[r][c] = COAL_ORE end
end end
end end
self.generated = true self.generated = true
self:render() self.r = chunkR
self:renderPerlin() self.c = chunkC
end end


function Chunk:generatePerlin(seed, chunkR, chunkC) function Chunk:generatePerlin(seed, chunkR, chunkC)
Expand Down Expand Up @@ -193,11 +190,15 @@ function Chunk:isGenerated()
end end


function Chunk:render() function Chunk:render()
if self.framebuffer == nil then
self.framebuffer = love.graphics.newFramebuffer(512, 512)
self.framebuffer:setFilter("linear", "nearest")
end
love.graphics.setRenderTarget(self.framebuffer) love.graphics.setRenderTarget(self.framebuffer)
love.graphics.setColor(255, 255, 255, 255) love.graphics.setColor(255, 255, 255, 255)
for r = 1, 32 do for r = 1, 32 do
for c = 1, 32 do for c = 1, 32 do
if self.block[r][c] ~= air then if self.block[r][c] ~= AIR and self.block[r][c] ~= UNGENERATED then
love.graphics.draw(images[self.block[r][c]], (c-1)*16, (r-1)*16) love.graphics.draw(images[self.block[r][c]], (c-1)*16, (r-1)*16)
end end
end end
Expand All @@ -206,11 +207,15 @@ function Chunk:render()
end end


function Chunk:renderPerlin() function Chunk:renderPerlin()
if self.framebufferPerlin == nil then
self.framebufferPerlin = love.graphics.newFramebuffer(512, 512)
self.framebufferPerlin:setFilter("linear", "nearest")
end
love.graphics.setRenderTarget(self.framebufferPerlin) love.graphics.setRenderTarget(self.framebufferPerlin)
love.graphics.setColor(255, 255, 255, 255) love.graphics.setColor(255, 255, 255, 255)
for r = 1, 32 do for r = 1, 32 do
for c = 1, 32 do for c = 1, 32 do
if self.block[r][c] ~= air then if self.block[r][c] ~= AIR then
love.graphics.setColor(128 + 80 * self.perlin[r][c], 128 + 80 * self.perlin[r][c], 128 + 80 * self.perlin[r][c], 255) love.graphics.setColor(128 + 80 * self.perlin[r][c], 128 + 80 * self.perlin[r][c], 128 + 80 * self.perlin[r][c], 255)
love.graphics.rectangle("fill", (c-1)*16, (r-1)*16, 16, 16) love.graphics.rectangle("fill", (c-1)*16, (r-1)*16, 16, 16)
end end
Expand Down
16 changes: 8 additions & 8 deletions collision.lua
Expand Up @@ -12,9 +12,9 @@ function checkCollisions(terrain, player)


-- Check right hit -- Check right hit
for y = 0, player.height, player.height/2 do for y = 0, player.height, player.height/2 do
if player.againstRightWall and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x + player.width/2 + 0.01)) ~= air then if player.againstRightWall and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x + player.width/2 + 0.01)) ~= AIR then
againstRightWall = true againstRightWall = true
elseif not player.againstRightWall and player.x > player.oldX and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x + player.width/2)) ~= air then elseif not player.againstRightWall and player.x > player.oldX and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x + player.width/2)) ~= AIR then
frac = (math.ceil(player.oldX + player.width/2) - (player.oldX + player.width/2)) / (player.x - player.oldX) frac = (math.ceil(player.oldX + player.width/2) - (player.oldX + player.width/2)) / (player.x - player.oldX)
mid = player.oldY - y + frac * (player.y - player.oldY) mid = player.oldY - y + frac * (player.y - player.oldY)
if mid >= math.ceil(player.y - y) - 1 and mid <= math.ceil(player.y - y) and frac < moveFrac then if mid >= math.ceil(player.y - y) - 1 and mid <= math.ceil(player.y - y) and frac < moveFrac then
Expand All @@ -25,9 +25,9 @@ function checkCollisions(terrain, player)
end--]] end--]]
-- Check left hit -- Check left hit
for y = 0, player.height, player.height/2 do for y = 0, player.height, player.height/2 do
if player.againstLeftWall and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x - player.width/2 - 0.01)) ~= air then if player.againstLeftWall and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x - player.width/2 - 0.01)) ~= AIR then
againstLeftWall = true againstLeftWall = true
elseif not player.againstLeftWall and player.x < player.oldX and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x - player.width/2)) ~= air then elseif not player.againstLeftWall and player.x < player.oldX and terrain:getBlock(math.ceil(player.y - y), math.ceil(player.x - player.width/2)) ~= AIR then
frac = (math.ceil(player.oldX - player.width/2) - 1 - (player.oldX - player.width/2)) / (player.x - player.oldX) frac = (math.ceil(player.oldX - player.width/2) - 1 - (player.oldX - player.width/2)) / (player.x - player.oldX)
mid = player.oldY - y + frac * (player.y - player.oldY) mid = player.oldY - y + frac * (player.y - player.oldY)
if mid >= math.ceil(player.y - y) - 1 and mid <= math.ceil(player.y - y) and frac < moveFrac then if mid >= math.ceil(player.y - y) - 1 and mid <= math.ceil(player.y - y) and frac < moveFrac then
Expand All @@ -39,7 +39,7 @@ function checkCollisions(terrain, player)
if player.falling then if player.falling then
-- Check ceiling hit -- Check ceiling hit
for x = -player.width/2, player.width, player.width do for x = -player.width/2, player.width, player.width do
if player.y < player.oldY and terrain:getBlock(math.ceil(player.y - player.height), math.ceil(player.x + x)) ~= air then if player.y < player.oldY and terrain:getBlock(math.ceil(player.y - player.height), math.ceil(player.x + x)) ~= AIR then
frac = (math.ceil(player.oldY - player.height) - 1 - (player.oldY - player.height)) / (player.y - player.oldY) frac = (math.ceil(player.oldY - player.height) - 1 - (player.oldY - player.height)) / (player.y - player.oldY)
mid = player.oldX + x + frac * (player.x - player.oldX) mid = player.oldX + x + frac * (player.x - player.oldX)
if mid >= math.ceil(player.x + x) - 1 and mid <= math.ceil(player.x + x) and frac < moveFrac then if mid >= math.ceil(player.x + x) - 1 and mid <= math.ceil(player.x + x) and frac < moveFrac then
Expand All @@ -50,7 +50,7 @@ function checkCollisions(terrain, player)
end--]] end--]]
-- Check ground hit -- Check ground hit
for x = -player.width/2, player.width, player.width do for x = -player.width/2, player.width, player.width do
if player.y > player.oldY and terrain:getBlock(math.ceil(player.y), math.ceil(player.x + x)) ~= air then if player.y > player.oldY and terrain:getBlock(math.ceil(player.y), math.ceil(player.x + x)) ~= AIR then
frac = (math.ceil(player.oldY) - (player.oldY)) / (player.y - player.oldY) frac = (math.ceil(player.oldY) - (player.oldY)) / (player.y - player.oldY)
mid = player.oldX + x + frac * (player.x - player.oldX) mid = player.oldX + x + frac * (player.x - player.oldX)
if mid >= math.ceil(player.x + x) - 1 and mid <= math.ceil(player.x + x) and frac < moveFrac then if mid >= math.ceil(player.x + x) - 1 and mid <= math.ceil(player.x + x) and frac < moveFrac then
Expand All @@ -61,8 +61,8 @@ function checkCollisions(terrain, player)
end--]] end--]]
else else
-- Check player has ground to stand on -- Check player has ground to stand on
if terrain:getBlock(math.floor(player.y) + 1, math.floor(player.x - player.width / 2) + 1) == air if terrain:getBlock(math.floor(player.y) + 1, math.floor(player.x - player.width / 2) + 1) == AIR
and terrain:getBlock(math.floor(player.y) + 1, math.floor(player.x + player.width / 2) + 1) == air then and terrain:getBlock(math.floor(player.y) + 1, math.floor(player.x + player.width / 2) + 1) == AIR then
player.falling = true player.falling = true
end end
end end
Expand Down
45 changes: 45 additions & 0 deletions generator.lua
@@ -0,0 +1,45 @@
this_thread = love.thread.getThread()
require("love.timer")
require("love.filesystem")
love.filesystem.load("TSerial.lua")()
love.filesystem.load("chunk.lua")()

-- Block codes
AIR = 0
STONE = 1
DIRT = 3
COAL_ORE = 16
UNGENERATED = 255

rand = {mySeed = 1, lastN = -1}
function rand:get(seed, n)
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 = -1
end
while self.lastN < n do
num = math.random()
self.lastN = self.lastN + 1
end
return num - 0.5
end

run = true

while run do
this_thread:send("ready", true)
commandMsg = this_thread:demand("command")
if commandMsg == "quit" then run = false
else
this_thread:send("ready", false)
local command = TSerial.unpack(commandMsg)
chunk = Chunk:new()
chunk:generate(command.seed, command.r, command.c)
this_thread:send("chunk", TSerial.pack(chunk))
end
end

0 comments on commit 4219d7c

Please sign in to comment.