eitmer/bundle/main.lua

336 lines
8.9 KiB
Lua
Raw Normal View History

2019-06-28 15:13:03 +00:00
local cavern = {}
local tiletypes = {unknown = 0, empty = 1, wall = 2}
local spawn_x = nil
local spawn_y = nil
local directions = {up = 0, upleft = 1, left = 2, downleft = 3, down = 4, downright = 5, right = 6, upright = 7}
local player_x = nil
local player_y = nil
local player_direction = nil
-- ------------------------------------------------------------------
-- Cavern generation
-- ------------------------------------------------------------------
function generateCavern()
repeat
cavern = {}
cavern.width = 80
cavern.height = 60
-- Create a cavern.width × cavern.height array filled with tiletypes.unknown
for x = 1, cavern.width do
local list = {}
for y = 1, cavern.height do
table.insert(list, tiletypes.unknown)
end
table.insert(cavern, list)
end
-- Fill top and bottom edges with walls
for x = 1, cavern.width do
cavern[x][1] = tiletypes.wall
cavern[x][cavern.height] = tiletypes.wall
end
-- Fill the left and right edges with walls
for y = 1, cavern.height do
cavern[1][y] = tiletypes.wall
cavern[cavern.width][y] = tiletypes.wall
end
local queue = {}
local size = 1
-- Limit spawn to locations not on the edge walls
spawn_x = math.random(2, cavern.width - 1)
spawn_y = math.random(2, cavern.height - 1)
cavern[spawn_x][spawn_y] = tiletypes.empty
table.insert(queue, {x = spawn_x, y = spawn_y - 1})
table.insert(queue, {x = spawn_x, y = spawn_y + 1})
table.insert(queue, {x = spawn_x - 1, y = spawn_y})
table.insert(queue, {x = spawn_x + 1, y = spawn_y})
repeat
queue, size = stepTilesGeneration(queue, size)
until #queue == 0
until size > 200
end
function stepTilesGeneration(queue, size)
-- Tuning this parameter will change how open and cavernous vs. closed and corridory the
-- cavern will be
local spread_probability = 0.6
local new_queue = {}
local new_size = size
for i, location in ipairs(queue) do
if cavern[location.x][location.y] == tiletypes.unknown then
-- We haven't covered this tile yet
if math.random() < spread_probability then
-- Empty
cavern[location.x][location.y] = tiletypes.empty
size = size + 1
-- Up
if location.y - 1 >= 1 then
table.insert(new_queue, {x = location.x, y = location.y - 1})
end
-- Down
if location.y + 1 <= cavern.height then
table.insert(new_queue, {x = location.x, y = location.y + 1})
end
-- Left
if location.x - 1 >= 1 then
table.insert(new_queue, {x = location.x - 1, y = location.y})
end
-- Right
if location.x + 1 <= cavern.width then
table.insert(new_queue, {x = location.x + 1, y = location.y})
end
else
-- Wall
cavern[location.x][location.y] = tiletypes.wall
end
end
end
return new_queue, size
end
-- ------------------------------------------------------------------
-- Spawning objects
-- ------------------------------------------------------------------
function spawnPlayer()
player_x = spawn_x
player_y = spawn_y
-- Check what direction we can spawn the player
if cavern[player_x][player_y + 1] == tiletypes.empty then
-- There's space under, spawn facing up
player_direction = directions.up
elseif cavern[player_x + 1][player_y] == tiletypes.empty then
-- There's space to the right, spawn facing left
player_direction = directions.left
elseif cavern[player_x - 1][player_y] == tiletypes.empty then
-- There's space to the left, spawn facing right
player_direction = directions.right
elseif cavern[player_x][player_y - 1] == tiletypes.empty then
-- There's space above, spawn facing down
player_direction = directions.down
else
error("Cavern is weirdly generated and player cannot spawn")
end
end
-- ------------------------------------------------------------------
-- Player helper functions
-- ------------------------------------------------------------------
function getBodyLocation(x, y, facing)
if x == nil then x = player_x end
if y == nil then y = player_y end
if facing == nil then facing = player_direction end
if facing == directions.up then
-- Facing up, body is down
return x, y + 1
elseif facing == directions.left then
-- Facing left, body is right
return x + 1, y
elseif facing == directions.down then
-- Facing down, body is up
return x, y - 1
elseif facing == directions.right then
-- Facing right, body is left
return x - 1, y
else
error("Player facing an impossible direction")
end
end
function movePlayer(direction)
local dx = 0
local dy = 0
local new_direction = direction
-- If we are moving backwards, keep the old direction of facing
if player_direction == directions.up and direction == directions.down or
player_direction == directions.down and direction == directions.up or
player_direction == directions.left and direction == directions.right or
player_direction == directions.right and direction == directions.left then
new_direction = player_direction
end
if direction == directions.up then
dy = -1
elseif direction == directions.down then
dy = 1
elseif direction == directions.left then
dx = -1
elseif direction == directions.right then
dx = 1
elseif direction == directions.upleft then
if player_direction == directions.down then
-- ## ##
-- x# xo#
-- #o# # #
dy = -1
new_direction = directions.right
elseif player_direction == directions.right then
-- # # #x#
-- #xo #o
-- ## ##
dx = -1
new_direction = directions.down
else
new_direction = player_direction
end
elseif direction == directions.downleft then
if player_direction == directions.up then
-- #o# # #
-- x# xo#
-- ## ##
dy = 1
new_direction = directions.right
elseif player_direction == directions.right then
-- ## ##
-- #xo #o
-- # # #x#
dx = -1
new_direction = directions.up
else
new_direction = player_direction
end
elseif direction == directions.downright then
if player_direction == directions.up then
-- #o# # #
-- #x #ox
-- ## ##
dy = 1
new_direction = directions.left
elseif player_direction == directions.left then
-- ## ##
-- ox# o#
-- # # #x#
dx = 1
new_direction = directions.up
else
new_direction = player_direction
end
elseif direction == directions.upright then
if player_direction == directions.down then
-- ## ##
-- #x #ox
-- #o# # #
dy = -1
new_direction = directions.left
elseif player_direction == directions.left then
-- # # #x#
-- ox# o#
-- ## ##
dx = 1
new_direction = directions.down
else
new_direction = player_direction
end
else
error("Player moving in an impossible direction")
end
local body_x, body_y = getBodyLocation(player_x + dx, player_y + dy, new_direction)
if cavern[player_x + dx][player_y + dy] == tiletypes.empty and
cavern[body_x][body_y] == tiletypes.empty then
player_x = player_x + dx
player_y = player_y + dy
player_direction = new_direction
end
end
-- ------------------------------------------------------------------
-- Callbacks
-- ------------------------------------------------------------------
function love.load()
math.randomseed(os.time())
generateCavern()
spawnPlayer()
end
function love.update(dt)
end
function love.keypressed(key)
if key == 'r' then
generateCavern()
spawnPlayer()
elseif key == 'i' then
movePlayer(directions.up)
elseif key == 'j' then
movePlayer(directions.left)
elseif key == 'k' then
movePlayer(directions.down)
elseif key == 'l' then
movePlayer(directions.right)
elseif key == 'u' then
movePlayer(directions.upleft)
elseif key == 'm' then
movePlayer(directions.downleft)
elseif key == '.' then
movePlayer(directions.downright)
elseif key == 'o' then
movePlayer(directions.upright)
elseif key == 'q' then
love.event.quit()
else
display_inputinfo_counter = 1
end
end
function love.draw()
local x_scale = love.graphics.getWidth() / cavern.width
local y_scale = love.graphics.getHeight() / cavern.height
-- Draw the cavern
for tile_x, list in ipairs(cavern) do
local x = (tile_x - 1) * x_scale
for tile_y, tile 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)
else
love.graphics.setColor(1, 0.5, 0.5)
end
love.graphics.rectangle('fill', x, y, x_scale, y_scale)
end
end
-- Draw the player
local player_head_center_x = (player_x - 1) * x_scale + 0.5 * x_scale
local player_head_center_y = (player_y - 1) * y_scale + 0.5 * y_scale
love.graphics.setColor(0.7, 0.3, 0.3)
love.graphics.ellipse('fill', player_head_center_x, player_head_center_y, x_scale/2, y_scale/2)
local player_body_x, player_body_y = getBodyLocation()
local player_body_x = (player_body_x - 1) * x_scale
local player_body_y = (player_body_y - 1) * y_scale
love.graphics.setColor(0, 0, 1)
love.graphics.rectangle('fill', player_body_x, player_body_y, x_scale, y_scale)
end