diff --git a/bundle/main.lua b/bundle/main.lua index ce8431e..efa459b 100644 --- a/bundle/main.lua +++ b/bundle/main.lua @@ -1,6 +1,9 @@ local cavern = {} local tiletypes = {unknown = 0, empty = 1, wall = 2} +local visibility_map = {} +local remembered_cavern = {} + local spawn_x = nil local spawn_y = nil @@ -56,12 +59,12 @@ function generateCavern() table.insert(queue, {x = spawn_x + 1, y = spawn_y}) repeat - queue, size = stepTilesGeneration(queue, size) + queue, size = stepCavernGeneration(queue, size) until #queue == 0 until size > 200 end -function stepTilesGeneration(queue, size) +function stepCavernGeneration(queue, size) -- Tuning this parameter will change how open and cavernous vs. closed and corridory the -- cavern will be local spread_probability = 0.6 @@ -133,6 +136,185 @@ function spawnPlayer() end end +-- ------------------------------------------------------------------ +-- Visibility +-- ------------------------------------------------------------------ + +function generateVisibilityMap() + -- Start by creating a new visibility map (since we'll have to recompute everything anyways) + visibility_map = {} + for x = 1, cavern.width do + local list = {} + for y = 1, cavern.height do + table.insert(list, false) + end + table.insert(visibility_map, list) + end + + -- Handle visibility from the head + local queue = {} + + if player_direction == directions.up then + -- ⌜^⌝ + -- + table.insert(queue, {x = player_x - 1, y = player_y - 1, direction = directions.upleft}) + table.insert(queue, {x = player_x, y = player_y - 1, direction = directions.up}) + table.insert(queue, {x = player_x + 1, y = player_y - 1, direction = directions.upright}) + + table.insert(queue, {x = player_x - 1, y = player_y, direction = directions.left}) + table.insert(queue, {x = player_x + 1, y = player_y, direction = directions.right}) + elseif player_direction == directions.left then + -- ⌜^ + -- + -- ⌞v⌟ + table.insert(queue, {x = player_x - 1, y = player_y, direction = directions.left}) + table.insert(queue, {x = player_x + 1, y = player_y, direction = directions.right}) + + table.insert(queue, {x = player_x - 1, y = player_y + 1, direction = directions.downleft}) + table.insert(queue, {x = player_x, y = player_y + 1, direction = directions.down}) + table.insert(queue, {x = player_x + 1, y = player_y + 1, direction = directions.downright}) + elseif player_direction == directions.right then + -- ^⌝ + -- o> + -- v⌟ + table.insert(queue, {x = player_x, y = player_y - 1, direction = directions.up}) + table.insert(queue, {x = player_x + 1, y = player_y - 1, direction = directions.upright}) + + table.insert(queue, {x = player_x + 1, y = player_y, direction = directions.right}) + + table.insert(queue, {x = player_x, y = player_y + 1, direction = directions.down}) + table.insert(queue, {x = player_x + 1, y = player_y + 1, direction = directions.downright}) + else + error("Player facing an impossible direction") + end + + repeat + queue = stepVisibilityMapGeneration(queue) + until #queue == 0 + + -- Handle "visibility" from the feet + local body_x, body_y = getBodyLocation() + + if player_direction == directions.up then + -- + -- v + visibility_map[body_x - 1][body_y] = true + visibility_map[body_x + 1][body_y] = true + + visibility_map[body_x][body_y + 1] = true + elseif player_direction == directions.left then + -- ^ + -- x> + -- v + visibility_map[body_x][body_y - 1] = true + + visibility_map[body_x + 1][body_y] = true + + visibility_map[body_x][body_y + 1] = true + elseif player_direction == directions.down then + -- ^ + -- + visibility_map[body_x][body_y - 1] = true + + visibility_map[body_x - 1][body_y] = true + visibility_map[body_x + 1][body_y] = true + elseif player_direction == directions.right then + -- ^ + -- + -- v⌟ + table.insert(new_queue, {x = item.x + 1, y = item.y, direction = directions.right}) + table.insert(new_queue, {x = item.x, y = item.y + 1, direction = directions.down}) + table.insert(new_queue, {x = item.x + 1, y = item.y + 1, direction = directions.downright}) + elseif item.direction == directions.upright then + -- ^⌝ + -- ⌝ x> + table.insert(new_queue, {x = item.x, y = item.y - 1, direction = directions.up}) + table.insert(new_queue, {x = item.x + 1, y = item.y - 1, direction = directions.upright}) + table.insert(new_queue, {x = item.x + 1, y = item.y, direction = directions.right}) + else + error("Visibility floodfill item travelling in an impossible direction") + end + end + end + + return new_queue +end + +function initializeRememberedCavern() + remembered_cavern = {} + for x = 1, cavern.width do + local list = {} + for y = 1, cavern.height do + table.insert(list, nil) + end + table.insert(remembered_cavern, list) + end +end + +function rememberVisible() + for x, list in ipairs(visibility_map) do + for y, visible in ipairs(list) do + if visible then + remembered_cavern[x][y] = cavern[x][y] + end + end + end +end + -- ------------------------------------------------------------------ -- Player helper functions -- ------------------------------------------------------------------ @@ -200,7 +382,7 @@ function movePlayer(direction) dx = -1 new_direction = directions.down else - new_direction = player_direction + error("Player facing an impossible direction") end elseif direction == directions.downleft then if player_direction == directions.up then @@ -222,7 +404,7 @@ function movePlayer(direction) dx = -1 new_direction = directions.up else - new_direction = player_direction + error("Player facing an impossible direction") end elseif direction == directions.downright then if player_direction == directions.up then @@ -244,7 +426,7 @@ function movePlayer(direction) dy = 1 new_direction = directions.down else - new_direction = player_direction + error("Player facing an impossible direction") end elseif direction == directions.upright then if player_direction == directions.up then @@ -266,7 +448,7 @@ function movePlayer(direction) dy = -1 new_direction = directions.up else - new_direction = player_direction + error("Player facing an impossible direction") end else error("Player moving in an impossible direction") @@ -291,6 +473,8 @@ function love.load() generateCavern() spawnPlayer() + generateVisibilityMap() + initializeRememberedCavern() end function love.update(dt) @@ -300,22 +484,40 @@ function love.keypressed(key) if key == 'r' then generateCavern() spawnPlayer() + generateVisibilityMap() + initializeRememberedCavern() elseif key == 'i' then + rememberVisible() movePlayer(directions.up) + generateVisibilityMap() elseif key == 'j' then + rememberVisible() movePlayer(directions.left) + generateVisibilityMap() elseif key == 'k' then + rememberVisible() movePlayer(directions.down) + generateVisibilityMap() elseif key == 'l' then + rememberVisible() movePlayer(directions.right) + generateVisibilityMap() elseif key == 'u' then + rememberVisible() movePlayer(directions.upleft) + generateVisibilityMap() elseif key == 'm' then + rememberVisible() movePlayer(directions.downleft) + generateVisibilityMap() elseif key == '.' then + rememberVisible() movePlayer(directions.downright) + generateVisibilityMap() elseif key == 'o' then + rememberVisible() movePlayer(directions.upright) + generateVisibilityMap() elseif key == 'q' then love.event.quit() else @@ -328,17 +530,30 @@ function love.draw() local y_scale = love.graphics.getHeight() / cavern.height -- Draw the cavern - for tile_x, list in ipairs(cavern) do + for tile_x, list in ipairs(visibility_map) do local x = (tile_x - 1) * x_scale - for tile_y, tile in ipairs(list) do + for tile_y, visible in ipairs(list) do local y = (tile_y - 1) * y_scale - if tile == tiletypes.empty then - love.graphics.setColor(0, 0, 0) - elseif tile == tiletypes.wall then - love.graphics.setColor(1, 1, 1) + if visible then + tile = cavern[tile_x][tile_y] + + if tile == tiletypes.empty then + love.graphics.setColor(0, 0, 0) + elseif tile == tiletypes.wall then + love.graphics.setColor(1, 1, 1) + else + love.graphics.setColor(1, 0.5, 0.5) + end else - love.graphics.setColor(1, 0.5, 0.5) + tile = remembered_cavern[tile_x][tile_y] + if tile == tiletypes.empty then + love.graphics.setColor(0.2, 0.2, 0.2) + elseif tile == tiletypes.wall then + love.graphics.setColor(0.8, 0.8, 0.8) + else + love.graphics.setColor(0.3, 0.3, 0.3) + end end love.graphics.rectangle('fill', x, y, x_scale, y_scale)