Created
March 8, 2018 21:03
-
-
Save Jacajack/36f6401a688dca45ff9734db84803275 to your computer and use it in GitHub Desktop.
Lua Love2D dungeon generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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