So I'm currently building a random maze generator, and for overall flexibility I want to be able to change map size in two simple variables, (SizeY and SizeX), but at the moment I'm unsure as how to construct a map table from these variables, I'm basically trying to make foo fill the map with walls (which are 2's in my code) according to SizeX and SizeY by using similar code to the love.graphics.draw for filling in the map, but I don't entirely understands how that works in the first place so I'm unsure how to adapt it to my purposes.
I looked at the http://www.lua.org/manual/5.1/manual.html#2.5.7 for info on tables but my brain basically melted trying to figure out what it all meant.
building a map from mapsize variable.
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
- forestwolf42
- Prole
- Posts: 24
- Joined: Tue Dec 20, 2011 5:18 pm
building a map from mapsize variable.
- Attachments
-
- MazeMaker.love
- Working this time.
- (624 Bytes) Downloaded 175 times
Last edited by forestwolf42 on Tue Jan 10, 2012 8:41 pm, edited 1 time in total.
Re: building a map from mapsize variable.
Did you package this correctly? I am not seeing any .lua files.
- forestwolf42
- Prole
- Posts: 24
- Joined: Tue Dec 20, 2011 5:18 pm
Re: building a map from mapsize variable.
Apparently not, let me fix that.
- forestwolf42
- Prole
- Posts: 24
- Joined: Tue Dec 20, 2011 5:18 pm
Re: building a map from mapsize variable.
I fixed it, sorry about that.
- Jasoco
- Inner party member
- Posts: 3727
- Joined: Mon Jun 22, 2009 9:35 am
- Location: Pennsylvania, USA
- Contact:
Re: building a map from mapsize variable.
I haven't looked at your code and it won't run without error, but I already created a mage generator I was (And probably still will) going to use for a game at some point. At some point I'm going to have to redo this better. This is the main.lua code:
Note: This will not run on 90% of Löve if not 100% as it's broken now in how it's displayed. Also, there are no images included since they're not relevant. All you need is the code that generates the maze. It's a TERRIBLE mess so don't complain. The MAIN code is in the function "createPath()".
It works by first creating a random path from the start square (room) off in a random direction for a specified time or until it closes itself in. The last square is marked as the end (exit or boss room) square. Then it loops a few times doing the same thing, but instead it first chooses a random square that A) is not the start, end or special room and B) has at least one empty neighbor. Then starts with one of those empty neighbors and draws a path until a specified time or it closes itself in. It also places special rooms, in this case what would have been a "key" room.
It can make a maze of any size if need be and can be set to fill in the entire grid or stop earlier.
I created this before anyone had even heard of Binding of Isaac.
Code: Select all
_r = math.random
_f = math.floor
_ce = math.ceil
_c = math.cos
_s = math.sin
_sq = math.sqrt
_at2 = math.atan2
_d2r = math.rad
_r2d = math.deg
_m = math.mod
_mx = math.max
_mn = math.min
pi = math.pi
gr = love.graphics
ti = love.timer
ms = love.mouse
kb = love.keyboard
math.randomseed(os.time())
math.randomseed(_r())
_r() _r() _r()
--require "savetable"
require "enemies"
require "behaviors"
require "maths"
love.filesystem.setIdentity("MapGen")
function love.run()
scrn = {}
scrn.w = 160
scrn.h = 144
scrn.ws = 3
scrn.fls = true
scrn.dox = -24
scrn.doy = -8
setScreenMode(scrn.ws)
hasBuffers, result = pcall(createBuffers)
love.load(arg)
gr.clear()
while true do
fps = ti.getFPS()
local dt = ti.getDelta()
ti.step()
time = ti.getTime()
gr.clear()
love.update(dt)
love.draw(dt)
if love.event then
for e,a,b,c in love.event.poll() do
if e == "q" then
if love.audio then love.audio.stop() end
return
end
love.handlers[e](a,b,c)
end
end
ti.sleep(.001)
gr.present()
end
end
function love.load(arg)
print("Arguments:")
for i, p in pairs(arg) do
print(p)
end
print(" ")
m = {}
gr.setLineWidth(1)
font1 = gr.newImageFont("font.png", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 :-!.,\"?>_", 0)
font2 = gr.newImageFont("font2.png", " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?-+/():;%&`_*#=[]'", 0)
font2:setLineHeight(.6)
font3 = gr.newImageFont("font3.png", " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-,:", 0)
font3:setLineHeight(.9)
font4 = gr.newFont(love._vera_ttf, 18)
font4:setLineHeight(1.4)
imgPlayer = gr.newImage("player.png")
quadPlayer = {}
for x=1,4 do
quadPlayer[x] = {}
for y=0,1 do
quadPlayer[x][y] = gr.newQuad((x-1)*16,y*16,16,16,imgPlayer:getWidth(),imgPlayer:getHeight())
end
end
imgTile = gr.newImage("room.png")
quadTile = {}
--QUADS WALL TOP
quadTile["wall_tl1"] = gr.newQuad(0,0,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_t1"] = gr.newQuad(16,0,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tdl1"] = gr.newQuad(32,0,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tdm1"] = gr.newQuad(48,0,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tdr1"] = gr.newQuad(64,0,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tr1"] = gr.newQuad(80,0,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tl2"] = gr.newQuad(0,16,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_t2"] = gr.newQuad(16,16,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tdl2"] = gr.newQuad(32,16,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tdm2"] = gr.newQuad(48,16,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tdr2"] = gr.newQuad(64,16,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_tr2"] = gr.newQuad(80,16,16,16,imgTile:getWidth(),imgTile:getHeight())
--QUADS WALL SIDES
quadTile["wall_l"] = gr.newQuad(0,80,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_ldt"] = gr.newQuad(0,32,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_ldb"] = gr.newQuad(0,48,16,32,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_r"] = gr.newQuad(80,80,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_rdt"] = gr.newQuad(80,32,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_rdb"] = gr.newQuad(80,48,16,32,imgTile:getWidth(),imgTile:getHeight())
--QUADS WALL BOTTOM
quadTile["wall_bl"] = gr.newQuad(0,96,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_b"] = gr.newQuad(16,96,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_bdl"] = gr.newQuad(32,96,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_bdm"] = gr.newQuad(48,96,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_bdr"] = gr.newQuad(64,96,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["wall_br"] = gr.newQuad(80,96,16,16,imgTile:getWidth(),imgTile:getHeight())
--QUADS FLOOR
quadTile["floor_db"] = gr.newQuad(0,112,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["floor_dt1"] = gr.newQuad(32,112,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["floor_dt2"] = gr.newQuad(16,112,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["floor_dr"] = gr.newQuad(48,112,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["floor_dl"] = gr.newQuad(64,112,16,16,imgTile:getWidth(),imgTile:getHeight())
quadTile["floor_1"] = gr.newQuad(80,112,16,16,imgTile:getWidth(),imgTile:getHeight())
--QUADS DOOR 1
quadTile["door_l_1"] = gr.newQuad(96,0,8,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_r_1"] = gr.newQuad(104,0,8,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_t_1"] = gr.newQuad(112,0,32,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_b_1"] = gr.newQuad(112,24,32,8,imgTile:getWidth(),imgTile:getHeight())
--QUADS DOOR 2 (Locked Door)
quadTile["door_l_2"] = gr.newQuad(96,0+32,8,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_r_2"] = gr.newQuad(104,0+32,8,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_t_2"] = gr.newQuad(112,0+32,32,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_b_2"] = gr.newQuad(112,24+32,32,8,imgTile:getWidth(),imgTile:getHeight())
--QUADS DOOR 3 (Boss Door)
quadTile["door_l_3"] = gr.newQuad(96,0+64,8,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_r_3"] = gr.newQuad(104,0+64,8,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_t_3"] = gr.newQuad(112,0+64,32,24,imgTile:getWidth(),imgTile:getHeight())
quadTile["door_b_3"] = gr.newQuad(112,24+64,32,8,imgTile:getWidth(),imgTile:getHeight())
player = {
x = 64, y = 64,
w = 12, h = 7,
hit,
mx, my,
speed = 64,
facing = 4,
step = 0,
stepFrame = 0,
hasMap = false
}
player.hit = {
x = (player.w / 2),
y = (player.h)
}
generateDungeon()
game.dungeon[player.mx][player.my].visited = true
gr.setBackgroundColor(0,0,0)
end
function love.update(dt)
m.x = _mn(_mx(_f((ms.getX() - scrn.ox) / scrn.s),0),scrn.w-1)
m.y = _mn(_mx(_f((ms.getY() - scrn.oy) / scrn.s),0),scrn.h-1)
local kSpace = kb.isDown(" ")
local kLeft = kb.isDown("left")
local kRight = kb.isDown("right")
local kUp = kb.isDown("up")
local kDown = kb.isDown("down")
local kShift = kb.isDown("lshift") or kb.isDown("rshift")
if game.isScrolling == false and game.paused == false then
local cx, cy
if kLeft and kRight == false then
player.facing = 1
player.moving = true
cx = player.x - dt * player.speed
cy = player.y
if checkTile(player.mx,player.my,cx-player.hit.x,cy-player.hit.y) == 0 and checkTile(player.mx,player.my,cx-player.hit.x,cy) == 0 then
player.x = cx
if player.x < 24 then
player.x = game.tw * 16
player.mx = player.mx - 1
game.scroll_h = -1
game.dungeon[player.mx][player.my].visited = true
end
end
elseif kRight and kLeft == false then
player.facing = 3
cx = player.x + dt * player.speed
cy = player.y
if checkTile(player.mx,player.my,cx+player.hit.x,cy-player.hit.y) == 0 and checkTile(player.mx,player.my,cx+player.hit.x,cy) == 0 then
player.x = cx
if player.x > game.tw * 16 then
player.x = 24
player.mx = player.mx + 1
game.scroll_h = 1
game.dungeon[player.mx][player.my].visited = true
end
end
end
if kUp and kDown == false then
player.facing = 2
cx = player.x
cy = player.y - dt * player.speed
if checkTile(player.mx,player.my,cx-player.hit.x,cy-player.hit.y) == 0 and checkTile(player.mx,player.my,cx+player.hit.x,cy-player.hit.y) == 0 then
player.y = cy
if player.y < 24 then
player.y = (game.th+.75) * 16
player.my = player.my - 1
game.scroll_v = -1
game.dungeon[player.mx][player.my].visited = true
end
end
elseif kDown and kUp == false then
player.facing = 4
cx = player.x
cy = player.y + dt * player.speed
if checkTile(player.mx,player.my,cx-player.hit.x,cy) == 0 and checkTile(player.mx,player.my,cx+player.hit.x,cy) == 0 then
player.y = cy
if player.y > (game.th+.75) * 16 then
player.y = 24
player.my = player.my + 1
game.scroll_v = 1
game.dungeon[player.mx][player.my].visited = true
end
end
end
if kLeft == false and kRight == false and kUp == false and kDown == false then
player.moving = false
else
player.moving = true
end
if player.moving then
player.step = player.step + dt * 8
if player.step > 1 then
player.step = 0
player.stepFrame = player.stepFrame + 1
if player.stepFrame > 1 then player.stepFrame = 0 end
end
end
for i, e in pairs(game.dungeon[player.mx][player.my].enemy) do
e:update(dt)
end
end
if game.scroll_h ~= 0 or game.scroll_v ~= 0 then
game.isScrolling = true
else
game.isScrolling = false
end
if game.scroll_h < 0 then
game.scroll_h = game.scroll_h + dt * game.scroll_s
if game.scroll_h > 0 then game.scroll_h = 0 end
elseif game.scroll_h > 0 then
game.scroll_h = game.scroll_h - dt * game.scroll_s
if game.scroll_h < 0 then game.scroll_h = 0 end
end
if game.scroll_v < 0 then
game.scroll_v = game.scroll_v + dt * game.scroll_s
if game.scroll_v > 0 then game.scroll_v = 0 end
elseif game.scroll_v > 0 then
game.scroll_v = game.scroll_v - dt * game.scroll_s
if game.scroll_v < 0 then game.scroll_v = 0 end
end
end
function checkTile(mx,my,cx,cy)
return game.dungeon[mx][my].tile[_f(cx/16)][_f(cy/16)].hit
end
function love.draw()
gr.setBlendMode("alpha")
gr.setCanvas(fb[1])
gr.setFont(font3)
local spw = (16*11)
local sph = (16*10)
if game.scroll_v ~= 0 or game.scroll_h ~= 0 then
if game.scroll_v < 0 then
drawLevel(player.mx, player.my+1, scrn.dox, scrn.doy + (sph * game.scroll_v) + sph)
drawLevel(player.mx, player.my , scrn.dox, scrn.doy + (sph * game.scroll_v))
elseif game.scroll_v > 0 then
drawLevel(player.mx, player.my-1, scrn.dox, scrn.doy + (sph * game.scroll_v) - sph)
drawLevel(player.mx, player.my , scrn.dox, scrn.doy + (sph * game.scroll_v))
end
if game.scroll_h < 0 then
drawLevel(player.mx+1, player.my, scrn.dox + (spw * game.scroll_h) + spw, scrn.doy)
drawLevel(player.mx , player.my, scrn.dox + (spw * game.scroll_h), scrn.doy)
elseif game.scroll_h > 0 then
drawLevel(player.mx-1, player.my, scrn.dox + (spw * game.scroll_h) - spw, scrn.doy)
drawLevel(player.mx , player.my, scrn.dox + (spw * game.scroll_h), scrn.doy)
end
else
drawLevel(player.mx, player.my, scrn.dox + spw * game.scroll_h, scrn.doy)
end
if game.paused == true then
gr.setFont(font1)
gr.setColor(0,0,0,100)
gr.rectangle("fill",0,0,scrn.w,scrn.h)
gr.setColor(0,0,0)
gr.print("PAUSED", 7*8, 9*8+1)
gr.setColor(255,255,255)
gr.print("PAUSED", 7*8, 9*8)
end
gr.setFont(font3)
t = "FPS: " .. fps .. "\nPlayer:\n" .. player.mx .. "," .. player.my .. "\n" .. _f(player.x) .. "," .. _f(player.y) .. "\n" .. _f(player.x/16) .. "," .. _f(player.y/16)
gr.setColor(0,0,0)
gr.print(t, 2, 3)
gr.setColor(255,255,255)
gr.print(t, 2, 2)
if showmap then drawMap(12, scrn.h - (game.sh * 8) - 12, 8) end
gr.setCanvas()
gr.setColor(0,0,0)
gr.rectangle("fill", 0, 0, gr.getWidth(), gr.getHeight())
gr.setColor(255,255,255)
gr.rectangle("fill", scrn.ox, scrn.oy, scrn.w * scrn.s, scrn.h * scrn.s)
gr.draw(fb[1], scrn.ox, scrn.oy, 0, scrn.s)
end
function drawMap(ox, oy, bs)
gr.setFont(font3)
for x=1,game.sw do
for y=1,game.sh do
local xx, yy = x-1, y-1
gr.setColor(255,255,255,100)
gr.rectangle("fill", ox + xx * bs, oy + yy * bs, bs, bs)
if game.dungeon[x][y].visited or player.hasMap then
if game.dungeon[x][y].type == "boss" then
gr.setColor(175,0,0)
elseif game.dungeon[x][y].type == "start" then
gr.setColor(0,175,0)
elseif game.dungeon[x][y].bosskey == true then
gr.setColor(175,175,0)
elseif game.dungeon[x][y].branch > 0 then
gr.setColor(100,100,100)
elseif game.dungeon[x][y].deadend == true then
gr.setColor(160,160,160)
elseif game.dungeon[x][y].mark == true then
gr.setColor(100,100,100)
else
gr.setColor(0,0,0,255)
end
gr.rectangle("fill", ox + xx * bs + 1, oy + yy * bs + 1, bs - 2, bs - 2)
local dh, ds = _ce(bs * .5 / 2), _ce(bs * .5)
local l, u, r, d = 1, 2, 3, 4
if game.dungeon[x][y].exit[l] > -1 then
if game.dungeon[x][y].exit[l] == 1 then
gr.setColor(0,0,0,200)
else
gr.setColor(255,0,0,200)
end
gr.rectangle("fill", ox + xx * bs, oy + yy * bs + (bs / 2) - dh, 1, ds)
end
if game.dungeon[x][y].exit[r] > -1 then
if game.dungeon[x][y].exit[r] == 1 then
gr.setColor(0,0,0,200)
else
gr.setColor(255,0,0,200)
end
gr.rectangle("fill", ox + xx * bs + (bs) - 1, oy + yy * bs + (bs / 2) - dh, 1, ds)
end
if game.dungeon[x][y].exit[u] > -1 then
if game.dungeon[x][y].exit[u] == 1 then
gr.setColor(0,0,0,200)
else
gr.setColor(255,0,0,200)
end
gr.rectangle("fill", ox + xx * bs + (bs / 2) - dh, oy + yy * bs, ds, 1)
end
if game.dungeon[x][y].exit[d] > -1 then
if game.dungeon[x][y].exit[d] == 1 then
gr.setColor(0,0,0,200)
else
gr.setColor(255,0,0,200)
end
gr.rectangle("fill", ox + xx * bs + (bs / 2) - dh, oy + yy * bs + (bs) - 1, ds, 1)
end
if debugVar then
gr.setColor(0,0,0,255)
gr.print(game.dungeon[x][y].depth, ox + xx * bs + 5, oy + yy * bs + 6)
end
end
end
end
if debugVar then
for rt, pp in pairs(game.path) do
j = 0
for i, p in pairs(game.path[rt].st) do
j = j + 1
gr.setColor(0,0,0,175)
--gr.print(j, p.x * game.tw + 7, p.y * game.th + 8)
gr.setColor(unpack(p.c))
if j > 1 then
gr.line(ox + p.x * bs + 3.5 - bs, oy + p.y * bs + 3.5 - bs, ox + game.path[rt].st[j-1].x * bs + 3.5 - bs, oy + game.path[rt].st[j-1].y * bs + 3.5 - bs)
end
gr.circle("fill", ox + p.x * bs + 4 - bs, oy + p.y * bs + 4 - bs, 2)
--gr.print(j, p.x * game.tw + 7, p.y * game.th + 7)
end
end
gr.setColor(0,255,0)
gr.circle("fill", ox + player.mx * bs + 4 - bs, oy + player.my * bs + 4 - bs, 2)
else
gr.setColor(0,255,0)
gr.circle("fill", ox + player.mx * bs + (bs / 2) - bs, oy + player.my * bs + (bs / 2) - bs, 2)
end
end
function drawLevel(mx,my,ox,oy)
ox = _f(ox)
oy = _f(oy)
for x=1,game.tw do
for y=0,game.th do
local f = game.dungeon[mx][my].tile[x][y].img.f
local w = game.dungeon[mx][my].tile[x][y].img.w
gr.setColor(255,255,255)
if f ~= "" then
gr.drawq(imgTile, quadTile[f], ox + x * 16, oy + y * 16)
end
if w ~= "" then
gr.drawq(imgTile, quadTile[w], ox + x * 16, oy + y * 16)
end
end
end
if game.dungeon[mx][my].door[1] > 0 then
gr.drawq(imgTile, quadTile["door_l_" .. game.dungeon[mx][my].door[1]], ox + 24, oy + 4.5 * 16)
end
if game.dungeon[mx][my].door[2] > 0 then
gr.drawq(imgTile, quadTile["door_t_" .. game.dungeon[mx][my].door[2]], ox + 5.5 * 16, oy + 8)
end
if game.dungeon[mx][my].door[3] > 0 then
gr.drawq(imgTile, quadTile["door_r_" .. game.dungeon[mx][my].door[3]], ox + (game.tw) * 16, oy + 4.5 * 16)
end
if game.dungeon[mx][my].door[4] > 0 then
gr.drawq(imgTile, quadTile["door_b_" .. game.dungeon[mx][my].door[4]], ox + 5.5 * 16, oy + (game.th) * 16)
end
if game.isScrolling == false then
for i, e in pairs(game.dungeon[mx][my].enemy) do
e:draw()
end
end
if mx == player.mx and my == player.my then
if checkPlayerColEnemy() > -1 then
gr.setColor(255,255,255)
gr.rectangle("fill", _f(ox + player.x - player.hit.x), _f(oy + player.y - player.hit.y), player.hit.x * 2, player.hit.y)
end
gr.setColor(0,0,0)
gr.point(_f(ox + player.x) + .5, _f(oy + player.y) + .5)
gr.setColor(255,255,255)
gr.drawq(imgPlayer,quadPlayer[player.facing][player.stepFrame], _f(ox + player.x), _f(oy + player.y) + 1, 0, 1, 1, 8, 16)
end
for x=1,game.tw do
for y=0,game.th do
local u = game.dungeon[mx][my].tile[x][y].img.u
gr.setColor(255,255,255)
if u ~= "" then
gr.drawq(imgTile, quadTile[u], ox + x * 16, oy + y * 16)
end
end
end
for x=0,game.tw*2-1 do
for y=0,game.th*2-1 do
--gr.setColor(0,0,0,100)
--gr.rectangle("fill", x*8, y*8, 7, 7)
end
end
end
function checkPlayerColEnemy()
local c = -1
for i, e in pairs(game.dungeon[player.mx][player.my].enemy) do
if c == -1 then
if overlap(player.x-player.hit.x, player.y-player.hit.y, player.w, player.h, e.x, e.y, e.w, e.h) then
c = e.id
end
end
end
return c
end
function overlap(x1,y1,w1,h1, x2,y2,w2,h2)
return not (x1+w1 < x2 or x2+w2 < x1 or y1+h1 < y2 or y2+h2 < y1)
end
function love.mousepressed(x, y, button)
if button == "l" then
elseif button == "r" then
elseif button == "m" then
elseif button == "wu" then
elseif button == "wd" then
end
end
function love.keypressed(k)
if k == " " then
for i=1,4 do
if kb.isDown("lshift") then
door(player.mx, player.my, i, 1)
else
door(player.mx, player.my, i, 0)
end
end
end
if k == "p" then
game.paused = not game.paused
end
if k == "m" then
showmap = not showmap
end
if k == "`" then
player.hasMap = true
end
if kb.isDown("lshift") and game.isScrolling == false then
if k == "left" then
if game.dungeon[player.mx][player.my].exit[1] > -1 then
player.mx = player.mx - 1
game.scroll_h = -1
end
elseif k == "up" then
if game.dungeon[player.mx][player.my].exit[2] > -1 then
player.my = player.my - 1
game.scroll_v = -1
end
elseif k == "right" then
if game.dungeon[player.mx][player.my].exit[3] > -1 then
player.mx = player.mx + 1
game.scroll_h = 1
end
elseif k == "down" then
if game.dungeon[player.mx][player.my].exit[4] > -1 then
player.my = player.my + 1
game.scroll_v = 1
end
end
end
if k == "escape" then
love.load()
end
if k == "tab" then
if kb.isDown("lalt") then
scrn.fls = not scrn.fls
updateScaling()
else
local modes = gr.getModes()
local mxs = _f(_mn(modes[1].width / scrn.w), _f((modes[1].height) / scrn.h))
if kb.isDown("lshift") then scrn.ws = scrn.ws - 1 else scrn.ws = scrn.ws + 1 end
if kb.isDown("lctrl") then scrn.ws = 0 end
if scrn.ws > mxs then scrn.ws = 0 end
if scrn.ws < 0 then scrn.ws = mxs end
setScreenMode(scrn.ws)
end
end
end
function love.focus(f)
if f then
else
game.paused = true
end
end
function generateDungeon()
stime = ti.getTime()
-- Set up Game Map
game = {
sw = _r(2,4)*2,
sh = _r(2,4)*2,
tw = 11,
th = 9,
scroll_h = 0,
scroll_v = 0,
scroll_s = 2,
isScrolling = false,
paused = false,
is = 8,
path = {},
dungeon = {},
seed = os.time()
}
math.randomseed(game.seed)
-- Set up Map Screens
local t
for x=0,game.sw+1 do
game.dungeon[x] = {}
for y=0,game.sh+1 do
if y <= game.sw/2 then t = "mtn" elseif x < game.sh/2+1 then t = "dst" else t = "frs" end
game.dungeon[x][y] = createRoom(t)
game.dungeon[x][y].enemy[#game.dungeon[x][y].enemy+1] = enemyPrototype.goomba:new(x, y, 5*16, 5*16)
game.dungeon[x][y].enemy[#game.dungeon[x][y].enemy+1] = enemyPrototype.goomba:new(x, y, 5.5*16, 5*16)
game.dungeon[x][y].enemy[#game.dungeon[x][y].enemy+1] = enemyPrototype.goomba:new(x, y, 6*16, 5*16)
game.dungeon[x][y].enemy[#game.dungeon[x][y].enemy+1] = enemyPrototype.goomba:new(x, y, 6.5*16, 5*16)
end
end
createPath()
local l, u, r, d = 1, 2, 3, 4
for x=0,game.sw+1 do
for y=0,game.sh+1 do
setTiles(x, y)
end
end
-- print(table.save(game.dungeon, true))
print("Generation time:", ti.getTime() - stime)
end
function door(x, y, dr, oc)
local dr2 = wrapDir(dr)
local x2, y2 = x, y
if x >= 1 and y >= 1 and x <= game.sw and y <= game.sh and game.dungeon[x][y].exit[dr] > -1 then
local l, u, r, d = 1, 2, 3, 4
game.dungeon[x][y].door[dr] = oc
if dr == l then
game.dungeon[x][y].tile[1][5].hit = oc
x2 = x - 1
elseif dr == u then
game.dungeon[x][y].tile[6][1].hit = oc
y2 = y - 1
elseif dr == r then
game.dungeon[x][y].tile[game.tw][5].hit = oc
x2 = x + 1
elseif dr == d then
game.dungeon[x][y].tile[6][game.th].hit = oc
y2 = y + 1
end
--Open other side of door too
game.dungeon[x2][y2].door[dr2] = oc
if dr2 == l then
game.dungeon[x2][y2].tile[1][5].hit = oc
elseif dr2 == u then
game.dungeon[x2][y2].tile[6][1].hit = oc
elseif dr2 == r then
game.dungeon[x2][y2].tile[game.tw][5].hit = oc
elseif dr2 == d then
game.dungeon[x2][y2].tile[6][game.th].hit = oc
end
print("DOOR", x, y, dr, "BDOOR", x2, y2, dr2)
end
end
function createRoom(t)
local r = {
exit = { [1] = -1, [2] = -1, [3] = -1, [4] = -1 },
door = { [1] = 0, [2] = 0, [3] = 0, [4] = 0 },
back = { [1] = {}, [2] = {}, [3] = {}, [4] = {} },
mark = false,
type = "room",
depth = -1,
branch = 0,
key = false,
bosskey = false,
deadend = false,
tile = {},
visited = false,
enemy = {}
}
for i=1,4 do
r.back[i] = { mx = -1, my = -1, d = -1 }
end
for x=0,game.tw+1 do
r.tile[x] = {}
for y=0,game.th+1 do
r.tile[x][y] = { hit = 1, img = { f = "", w = "", u = "" } }
end
end
for x=2,game.tw-1 do
for y=2,game.th-1 do
r.tile[x][y].hit = 0
end
end
return r
end
function setTiles(x, y)
local l, u, r, d = 1, 2, 3, 4
for x2=1,game.tw-1 do
for y2=1,game.th-1 do
game.dungeon[x][y].tile[x2][y2].img.f = "floor_1"
end
end
game.dungeon[x][y].tile[1][0].img.w = "wall_tl1"
game.dungeon[x][y].tile[1][1].img.w = "wall_tl2"
game.dungeon[x][y].tile[game.tw][0].img.w = "wall_tr1"
game.dungeon[x][y].tile[game.tw][1].img.w = "wall_tr2"
game.dungeon[x][y].tile[1][game.th].img.w = "wall_bl"
game.dungeon[x][y].tile[game.tw][game.th].img.w = "wall_br"
for x2 = 2, game.tw-1 do
game.dungeon[x][y].tile[x2][0].img.w = "wall_t1"
game.dungeon[x][y].tile[x2][1].img.w = "wall_t2"
game.dungeon[x][y].tile[x2][game.th].img.w = "wall_b"
end
for y2 = 2, game.th-1 do
game.dungeon[x][y].tile[1][y2].img.w = "wall_l"
game.dungeon[x][y].tile[game.tw][y2].img.w = "wall_r"
end
for i = 1, 4 do
if i == l and game.dungeon[x][y].exit[l] > 0 then
game.dungeon[x][y].tile[1][4].img.w = "wall_ldt"
game.dungeon[x][y].tile[1][5].img.w = ""
game.dungeon[x][y].tile[1][4].img.u = "wall_ldb"
game.dungeon[x][y].tile[1][5].img.f = "floor_dl"
elseif i == u and game.dungeon[x][y].exit[u] > 0 then
game.dungeon[x][y].tile[5][0].img.w = "wall_tdl1"
game.dungeon[x][y].tile[5][1].img.w = "wall_tdl2"
game.dungeon[x][y].tile[6][0].img.u = "wall_tdm1"
game.dungeon[x][y].tile[6][0].img.w = ""
game.dungeon[x][y].tile[6][1].img.w = ""
game.dungeon[x][y].tile[7][0].img.w = "wall_tdr1"
game.dungeon[x][y].tile[7][1].img.w = "wall_tdr2"
game.dungeon[x][y].tile[6][0].img.f = "floor_dt1"
game.dungeon[x][y].tile[6][1].img.f = "floor_dt2"
elseif i == r and game.dungeon[x][y].exit[r] > 0 then
game.dungeon[x][y].tile[game.tw][4].img.w = "wall_rdt"
game.dungeon[x][y].tile[game.tw][5].img.w = ""
game.dungeon[x][y].tile[game.tw][4].img.u = "wall_rdb"
game.dungeon[x][y].tile[game.tw][5].img.f = "floor_dr"
elseif i == d and game.dungeon[x][y].exit[d] > 0 then
game.dungeon[x][y].tile[5][game.th].img.w = "wall_bdl"
game.dungeon[x][y].tile[6][game.th].img.w = ""
game.dungeon[x][y].tile[6][game.th].img.u = "wall_bdm"
game.dungeon[x][y].tile[7][game.th].img.w = "wall_bdr"
game.dungeon[x][y].tile[6][game.th].img.f = "floor_db"
end
end
end
function createPath()
local tmpEmpty = {}
local runthrough = 1
local filled = false
local l, u, r, d = 1, 2, 3, 4
local nr, mnr, c
repeat
local rt = runthrough
local i = 1
local k = 0
c = {_r(50,150),_r(50,150),_r(50,150)}
if runthrough == 1 then
local xx = _r(1,game.sw)
local yy = game.sh
game.path[1] = { x = xx, y = yy, cx = xx, cy = yy, sx = xx, sy = yy, st = {}, bel, applic = true }
player.mx = xx
player.my = yy
done = false
game.path[rt].st[1] = { x = game.path[1].x, y = game.path[1].y, d = 0, c = c }
game.dungeon[game.path[1].x][game.path[1].y].type = "start"
else
local te = _r(1,#tmpEmpty)
game.path[rt] = { x, y, cx, cy, sx = tmpEmpty[te].x, sy = tmpEmpty[te].y, st = {}, bel }
done = false
game.path[rt].x = game.path[rt].sx
game.path[rt].y = game.path[rt].sy
local x, y, neigh = -1, -1, {}
for h=1,4 do
if h == l then
if game.dungeon[game.path[rt].x-1][game.path[rt].y].mark == true then
neigh[#neigh+1] = { x = game.path[rt].x-1, y = game.path[rt].y, d = h }
end
elseif h == u then
if game.dungeon[game.path[rt].x][game.path[rt].y-1].mark == true then
neigh[#neigh+1] = { x = game.path[rt].x, y = game.path[rt].y-1, d = h }
end
elseif h == r then
if game.dungeon[game.path[rt].x+1][game.path[rt].y].mark == true then
neigh[#neigh+1] = { x = game.path[rt].x+1, y = game.path[rt].y, d = h }
end
elseif h == d then
if game.dungeon[game.path[rt].x][game.path[rt].y+1].mark == true then
neigh[#neigh+1] = { x = game.path[rt].x, y = game.path[rt].y+1, d = h }
end
end
end
if #neigh > 0 then
local r = _r(1,#neigh)
x = neigh[r].x
y = neigh[r].y
dr = wrapDir(neigh[r].d)
game.path[rt].st[1] = { x = x, y = y, d = dr, c = c }
game.dungeon[x][y].exit[dr] = 1
game.dungeon[x][y].door[dr] = 1
game.dungeon[x][y].branch = game.dungeon[x][y].branch - 1
game.path[rt].st[2] = { x = game.path[rt].x, y = game.path[rt].y, d = neigh[r].d, c = c }
i = i + 1
else
game.path[rt].st[1] = { x = game.path[rt].x, y = game.path[rt].y, d = 0, c = c }
end
end
mnr = _r(3,10)
game.dungeon[game.path[rt].x][game.path[rt].y].mark = true
nr = 1
while done == false do
--Choose Direction
dr = _r(1,4)
local loop = true
local j = 0
while loop == true do
j = j + 1
--Check Direction
if dr == l then
game.path[rt].cx = game.path[rt].x-1
game.path[rt].cy = game.path[rt].y
elseif dr == u then
game.path[rt].cx = game.path[rt].x
game.path[rt].cy = game.path[rt].y-1
elseif dr == r then
game.path[rt].cx = game.path[rt].x+1
game.path[rt].cy = game.path[rt].y
elseif dr == d then
game.path[rt].cx = game.path[rt].x
game.path[rt].cy = game.path[rt].y+1
end
if game.path[rt].cx > 0 and game.path[rt].cy > 0 and game.path[rt].cx < game.sw + 1 and game.path[rt].cy < game.sh + 1 then
nb = game.dungeon[game.path[rt].cx][game.path[rt].cy].mark
if nb == false then
nr = nr + 1
game.dungeon[game.path[rt].cx][game.path[rt].cy].mark = true
game.dungeon[game.path[rt].x][game.path[rt].y].exit[dr] = 1
game.dungeon[game.path[rt].x][game.path[rt].y].door[dr] = 1
i = i + 1
game.path[rt].st[i] = { x = game.path[rt].cx, y = game.path[rt].cy, d = dr, c = c }
game.path[rt].x = game.path[rt].cx
game.path[rt].y = game.path[rt].cy
loop = false
k = k + 1
end
end
if j >= 20 then
loop = false
k = k + 1
end
end
if k >= 100 or nr >= mnr then
done = true
end
end
tmpEmpty = {}
local f = 0
local f2 = 0
for x=1,game.sw do
for y=1,game.sh do
if game.dungeon[x][y].mark == false then
f = f + 1
if game.dungeon[x-1][y].mark or game.dungeon[x][y-1].mark or game.dungeon[x+1][y].mark or game.dungeon[x][y+1].mark then
f2 = f2 + 1
tmpEmpty[f2] = { x = x, y = y }
end
end
end
end
if f == 0 then
filled = true
end
runthrough = runthrough + 1
if runthrough > 1000 then
filled = true
end
until filled == true
local lng = { path = 0, len = 0 }
for i, p in pairs(game.path) do
local l = #p.st
if l > lng.len and game.dungeon[p.st[#p.st].x][p.st[#p.st].y].branch == 0 then
lng.len = l
lng.path = i
end
game.dungeon[p.st[#p.st].x][p.st[#p.st].y].deadend = true
end
local dx, dy = game.path[lng.path].st[lng.len].x, game.path[lng.path].st[lng.len].y
local dx2, dy2 = game.path[lng.path].st[lng.len-1].x, game.path[lng.path].st[lng.len-1].y
game.dungeon[dx][dy].type = "boss"
-- print(game.path[lng.path].st[lng.len].x, game.path[lng.path].st[lng.len].y)
-- print(game.path[lng.path].st[lng.len-1].x, game.path[lng.path].st[lng.len-1].y)
--FIND ALL DEAD ENDS
local potenkey = {}
for x=1,game.sw do
for y=1,game.sh do
if game.dungeon[x][y].deadend == true and game.dungeon[x][y].type == "room" then
potenkey[#potenkey+1] = { x = x, y = y }
end
end
end
--PLACE BOSS KEY
local kr = _r(1,#potenkey)
game.dungeon[potenkey[kr].x][potenkey[kr].y].bosskey = true
--MARK ROOM DEPTH
local sdepth = 0
for i, p in pairs(game.path) do
for j=1,#p.st do
if j == 1 then
if i == 1 then
sdepth = 0
else
sdepth = game.dungeon[p.st[j].x][p.st[j].y].depth
end
else
sdepth = sdepth + 1
end
game.dungeon[p.st[j].x][p.st[j].y].depth = sdepth
end
end
--MARK DOORS
for x=1,game.sw do
for y=1,game.sh do
if game.dungeon[x][y].exit[l] > 0 then
game.dungeon[x-1][y].exit[r] = 1
game.dungeon[x-1][y].door[r] = 1
game.dungeon[x][y].back[l] = { mx = x - 1, my = y, d = r }
end
if game.dungeon[x][y].exit[r] > 0 then
game.dungeon[x+1][y].exit[l] = 1
game.dungeon[x+1][y].door[l] = 1
game.dungeon[x][y].back[r] = { mx = x + 1, my = y, d = l }
end
if game.dungeon[x][y].exit[u] > 0 then
game.dungeon[x][y-1].exit[d] = 1
game.dungeon[x][y-1].door[d] = 1
game.dungeon[x][y].back[u] = { mx = x, my = y - 1, d = d }
end
if game.dungeon[x][y].exit[d] > 0 then
game.dungeon[x][y+1].exit[u] = 1
game.dungeon[x][y+1].door[u] = 1
game.dungeon[x][y].back[d] = { mx = x, my = y + 1, d = u }
end
end
end
--Lock the Boss Door with the special Boss Key lock
for i=1,4 do
door(dx, dy, i, 3)
end
end
function wrapDir(n)
n = n + 2
if n == 5 then n = 1 end
if n == 6 then n = 2 end
return n
end
function setScreenMode(s)
if s == 0 then
modes = gr.getModes()
gr.setMode(modes[1].width, modes[1].height, true, false)
else
gr.setMode(scrn.w * s, scrn.h * s, false, false)
end
updateScaling()
end
function updateScaling()
scrn.s = _mn(gr.getWidth() / scrn.w, gr.getHeight() / scrn.h)
if scrn.fls then
scrn.s = _f(scrn.s)
end
scrn.ox = (gr.getWidth() - (scrn.w * scrn.s)) / 2
scrn.oy = (gr.getHeight() - (scrn.h * scrn.s)) / 2
end
function distanceFrom(x1,y1,x2,y2) return _sq((x2 - x1) ^ 2 + (y2 - y1) ^ 2) end
function degToRad(d) return d * pi / 180 end
function sort(T) table.sort(T, function(a, b) return a.y < b.y end ) end
function formatNumber(number)
return (string.format("%d", number):reverse():gsub( "(%d%d%d)" , "%1," ):reverse():gsub("^(-?),","%1"))
end
function createBuffers()
fb = {
[1] = gr.newCanvas(1024, 1024)
}
for i, f in pairs(fb) do
f:setFilter("nearest", "nearest")
end
return true
end
It works by first creating a random path from the start square (room) off in a random direction for a specified time or until it closes itself in. The last square is marked as the end (exit or boss room) square. Then it loops a few times doing the same thing, but instead it first chooses a random square that A) is not the start, end or special room and B) has at least one empty neighbor. Then starts with one of those empty neighbors and draws a path until a specified time or it closes itself in. It also places special rooms, in this case what would have been a "key" room.
It can make a maze of any size if need be and can be set to fill in the entire grid or stop earlier.
I created this before anyone had even heard of Binding of Isaac.
- Attachments
-
- MapGen.love
- Use at your own risk. It probably won't run at all.
- (55.68 KiB) Downloaded 183 times
- forestwolf42
- Prole
- Posts: 24
- Joined: Tue Dec 20, 2011 5:18 pm
Re: building a map from mapsize variable.
I have looked at that, but it's not really relevant to my question of making the starting map table based off of two variables, instead of simply filling a pre-made table.MarekkPie wrote:http://en.wikipedia.org/wiki/Maze_generation_algorithm
This would be a good place to start.
Re: building a map from mapsize variable.
Well, if you just want to build a table of size WIDTH, HEIGHT, just:
At that point, then follow one of the algorithms in that wikipedia article. If that still isn't what you need, then I have no idea what you're asking.
Code: Select all
map = {}
for j, HEIGHT do
for i, WIDTH do
table.insert(map, {x = i, y = j, visited = false})
end
end
- Jasoco
- Inner party member
- Posts: 3727
- Joined: Mon Jun 22, 2009 9:35 am
- Location: Pennsylvania, USA
- Contact:
Re: building a map from mapsize variable.
As I said, you start with a grid of a certain size:
Is my preferred grid creation method.
Pick a random start point. Draw a random path in random directions until you either reach a preset destination or box yourself in. Then repeat the path-finding algorithm by choosing a starting point with at least one empty neighbor and draw paths out in the same manner until either all squares are filled or you have drawn the required amount of paths depending on how you want the maze to look.
If you want you can even pre-mark squares as "unusable" to make a pattern and have it fill that in so you can create dungeons with neat shapes instead of solid blocks.
That's basically the gist. It took a while for me to even do that myself and am going to have to recode it again at some point in the future to be more modern. But it works. (At least the maze part. The graphical end is screwed up in my example because it's a hybrid of multiple versions of 0.8.0 but was created during 0.7.2.
Code: Select all
map = {}
for x = 0, mapWidth - 1 do
map[x] = {}
for y = 0, mapHeight - 1 do
map[x][y] = { marked = false }
end
end
Pick a random start point. Draw a random path in random directions until you either reach a preset destination or box yourself in. Then repeat the path-finding algorithm by choosing a starting point with at least one empty neighbor and draw paths out in the same manner until either all squares are filled or you have drawn the required amount of paths depending on how you want the maze to look.
If you want you can even pre-mark squares as "unusable" to make a pattern and have it fill that in so you can create dungeons with neat shapes instead of solid blocks.
That's basically the gist. It took a while for me to even do that myself and am going to have to recode it again at some point in the future to be more modern. But it works. (At least the maze part. The graphical end is screwed up in my example because it's a hybrid of multiple versions of 0.8.0 but was created during 0.7.2.
Re: building a map from mapsize variable.
Jasoco's map maker is better; the node coordinates are indexed as they should be for a matrix.
Who is online
Users browsing this forum: Google [Bot] and 0 guests