336 lines
8.9 KiB
Lua
336 lines
8.9 KiB
Lua
|
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
|