Skip to content

Instantly share code, notes, and snippets.

@Jacajack
Created March 8, 2018 21:03
Show Gist options
  • Save Jacajack/36f6401a688dca45ff9734db84803275 to your computer and use it in GitHub Desktop.
Save Jacajack/36f6401a688dca45ff9734db84803275 to your computer and use it in GitHub Desktop.
Lua Love2D dungeon generator
function mkroom(x, y, w, h, id)
local room = {
x = x,
y = y,
w = w,
h = h,
adj = {},
id = id or 0
};
return room
end
function roomcoll(a, b, margin)
margin = margin or 10
if a == b then return false else
return math.abs(a.x - b.x) < (a.w + b.w) / 2 + margin and math.abs(a.y - b.y) < (a.h + b.h) / 2 + margin
end
end
function spread(x, y, r, cnt)
local rooms = {}
for i = 1, cnt do
local ang = love.math.random() * 2 * math.pi
local r = love.math.random() * r
local x = x + math.floor(math.cos(ang) * r)
local y = y + math.floor(math.sin(ang) * r)
local w = math.floor(love.math.random(15, 60))
local h = math.floor(love.math.random(15, 60))
rooms[i] = mkroom(x, y, w, h, i)
end
return rooms
end
function cleanup(rooms, cnt)
for i = #rooms, 1, -1 do
for j = #rooms, 1, -1 do
if rooms[i] and rooms[j] and roomcoll(rooms[i], rooms[j]) == true then
table.remove(rooms, j)
end
end
end
cnt = #rooms - cnt
for i = 1, cnt do
table.remove(rooms, 1)
end
return rooms
end
function mknet(rooms)
local net = {}
for i = 1, #rooms do
for j = 1, #rooms do
if i ~= j then
local dist = math.sqrt((rooms[i].x - rooms[j].x) ^ 2 + (rooms[i].y - rooms[j].y) ^ 2)
net[#net + 1] = {rooms[i], rooms[j], dist = dist, act = true}
table.insert(rooms[i].adj, rooms[j])
table.insert(rooms[j].adj, rooms[i])
end
end
end
return net
end
function spantree(rooms, net)
function fill(rooms, idtar, idnew)
for i = 1, #rooms do
if rooms[i].id == idtar then
rooms[i].id = idnew
end
end
end
function getmin(net)
local best = 10e9
local besti = 0
for i = 1, #net do
local conn = net[i]
if conn.dist < best then
best = conn.dist
besti = i
end
end
return besti
end
local done = {}
while #net > 0 do
local besti = getmin(net)
local best = net[besti]
if best[1].id ~= best[2].id then
fill(rooms, best[1].id, best[2].id)
done[#done + 1] = best
end
table.remove(net, besti)
end
return done
end
--Please note, that each corridor can be represented with a room as well!
function net2halls(net)
local halls = {}
for i = 1, #net do
local conn = net[i]
local a = conn[1]
local b = conn[2]
local mx, my
if love.math.random() < 0.5 then
mx = a.x
my = b.y
else
mx = b.x
my = a.y
end
halls[#halls + 1] = {a.x, a.y, mx, my, b.x, b.y}
end
return halls
end
function generate()
rooms = spread(400, 300, 200, 100)
rooms = cleanup(rooms, 20)
net = mknet(rooms)
net = spantree(rooms, net)
halls = net2halls(net)
end
function love.load()
love.window.setMode(800, 600, {msaa = 0})
love.window.setTitle("Dungeon generator")
generate()
shownet = false
end
function love.keypressed(key, scancode, isrepeat)
if key == "space" then
generate()
end
if key == "n" then
shownet = not shownet
end
end
function love.draw()
--Draw corridors
love.graphics.setLineWidth(5)
love.graphics.setColor(40, 100, 140, 255)
for i = 1, #halls do
love.graphics.line(halls[i])
end
--Draw rooms
love.graphics.setLineWidth(3)
for i = 1, #rooms do
love.graphics.setColor(40, 80, 120, 255)
love.graphics.rectangle("fill", rooms[i].x - rooms[i].w / 2, rooms[i].y - rooms[i].h / 2, rooms[i].w, rooms[i].h)
love.graphics.setColor(40, 100, 140, 255)
love.graphics.rectangle("line", rooms[i].x - rooms[i].w / 2, rooms[i].y - rooms[i].h / 2, rooms[i].w, rooms[i].h)
end
--Draw net (debug only)
if shownet == true then
love.graphics.setLineWidth(1)
love.graphics.setColor(200, 200, 200, 128)
for i = 1, #net do
love.graphics.line(net[i][1].x, net[i][1].y, net[i][2].x, net[i][2].y)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment