Mazer - tool to create mazes

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
User avatar
darkfrei
Party member
Posts: 1169
Joined: Sat Feb 08, 2020 11:09 pm

Mazer - tool to create mazes

Post by darkfrei »

Hi all!

There is a tool, that creates random full-connected mazes with any size in two formats:

Code: Select all

-- cell has walls at top and right:
cell = {up=true, down=false, left=false, right=true}
maze[y][x] = cell
and as grid of bools:
(wall thickness and cell sizes are adjustable)

Code: Select all

-- wall:
grid[y][x] = true

-- not wall:
grid[y][x] = false
Example with grid (gray rectangles) and maze (white lines):
mazer-01.png
mazer-01.png (20.57 KiB) Viewed 1361 times

Code: Select all

-- mazer.lua
-- tool to create mazes

-- cc0 (no license)
-- darkfrei 2023

local mazer = {}

local function shuffle (list)
	-- backward iteration from last to second element:
	for i = #list, 2, -1 do
		-- choose one of elements:
		local j = love.math.random(i) -- between 1 to i (both inclusive)
		-- replace both elements each other:
		list[i], list[j] = list[j], list[i]
	end
	return list
end

local oppositeTable = {
	up = "down",
	down = "up",
	left = "right",
	right = "left",
}

local function opposite (sideName)
	return oppositeTable[sideName]
end

local function visit(maze, x, y)
	local directions = {{0, -1, "up"}, {0, 1, "down"}, {-1, 0, "left"}, {1, 0, "right"}}
	for _, dir in ipairs(shuffle (directions)) do
		local nx, ny = x + dir[1], y + dir[2]
		local exist = maze[ny] and maze[ny][nx]
		if exist and not (maze[ny][nx].visited) then
			local sideName = dir[3]
			maze[y][x][sideName] = false
			local oppositeSide = opposite (sideName)
			maze[ny][nx][oppositeSide] = false
			maze[ny][nx].visited = true
			visit(maze, nx, ny)
		end
	end
end

function mazer.generateMaze(width, height, startX, startY)
	local maze = {}
  for y = 1, height do
    maze[y] = {}
    for x = 1, width do
      local cell = {up=true, down=true, left=true, right=true, visited = false}
			maze[y][x] = cell
    end
  end

  startX = startX or love.math.random(width)
  startY = startY or love.math.random(height)
  maze[startY][startX].visited = true
  visit(maze, startX, startY)
	
	for y, xs in ipairs (maze) do
		for x, cell in ipairs (xs) do
			cell.visited = nil
		end
	end
  
  return maze
end

local function removeWallFromGrid (grid, x1, y1, x2, y2, wall)
	for gy = y1, y2 do
		for gx = x1, x2 do
			grid[gy][gx] = not wall
		end
	end
end

function mazer.createGrid (maze, wallSize, cellSize)
--	wallSize = 2
--	cellSize = 4
	local stepSize = wallSize + cellSize -- 6
	local h = wallSize + #maze*stepSize
	local w = wallSize + #maze[1]*stepSize
	
	local wall = true
	
	local grid = {}
	for gy = 1, h do
		grid[gy] = {}
		for gx = 1, w do
			grid[gy][gx] = wall
		end
	end
	
	for y, xs in ipairs (maze) do
		local gy1 = 1 + (y-1)*stepSize
		local gy2 = gy1 + stepSize + wallSize - 1
		for x, cell in ipairs (xs) do
			local gx1 = 1 + (x-1)*stepSize
			local gx2 = gx1 + stepSize + wallSize - 1
			
			removeWallFromGrid (grid, gx1 + wallSize, gy1 + wallSize, gx2-wallSize, gy2-wallSize, wall)
			
			if not cell.right then
				removeWallFromGrid (grid, gx1 + stepSize, gy1 + wallSize, gx2, gy2-wallSize, wall)
--				for gy = gy1 + wallSize, gy2-wallSize do
--					for gx = gx1 + stepSize, gx2 do
--						grid[gy][gx] = not wall
--					end
--				end
			end
			if not cell.left then
				removeWallFromGrid (grid, gx1, gy1 + wallSize, gx2-stepSize, gy2-wallSize, wall)
			end
			if not cell.up then
				removeWallFromGrid (grid, gx1+wallSize, gy1, gx2-wallSize, gy2-stepSize, wall)
			end
			if not cell.down then
				removeWallFromGrid (grid, gx1+wallSize, gy1+stepSize, gx2-wallSize, gy2, wall)
			end

		end
	end
	return grid
end

function mazer.drawMaze (maze)
	for y, xs in ipairs (maze) do
		for x, cell in ipairs (xs) do
			if cell.right then	love.graphics.line (x,   y-1, x,   y) end
			if cell.left 	then	love.graphics.line (x-1, y-1, x-1, y) end
			if cell.up 		then	love.graphics.line (x-1, y-1, x, y-1) end
			if cell.down 	then	love.graphics.line (x-1, y,   x,   y) end
		end
	end
end

function mazer.drawGrid (grid, gridSize, mode)
	gridSize = gridSize or 16
	mode = mode or 'fill'
	for y, xs in ipairs (grid) do
		for x, bool in ipairs (xs) do
			if bool then
				love.graphics.rectangle (mode, (x-1)*gridSize, (y-1)*gridSize, gridSize, gridSize)
			end
		end
	end
end

return mazer
Attachments
mazer-01.love
CC0 - no license
(1.68 KiB) Downloaded 70 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Mazer - tool to create mazes

Post by pgimeno »

Feel free to add it to this thread: https://love2d.org/forums/viewtopic.php?f=5&t=19873
User avatar
darkfrei
Party member
Posts: 1169
Joined: Sat Feb 08, 2020 11:09 pm

Re: Mazer - tool to create mazes

Post by darkfrei »

New version:
the top left cell always has a floor;
default maze creating is from bottom right cell.
mazer-02.png
mazer-02.png (10.65 KiB) Viewed 1259 times
Attachments
mazer-02.love
(1.74 KiB) Downloaded 64 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1169
Joined: Sat Feb 08, 2020 11:09 pm

Re: Mazer - tool to create mazes

Post by darkfrei »

New version, combined with tiles-to-rectangles.lua, so it generates the list of rectangles as

Code: Select all

rectangles = {
	{x=x1, y=y1, w=w1, h=h1},
	{x=x2, y=y2, w=w2, h=h2},
	--...
}

Code: Select all

love.graphics.scale(16)
love.graphics.setLineWidth(1/8)

for i, r in ipairs (rectangles) do
	love.graphics.setColor(0.5,0.5,0.5)
	love.graphics.rectangle('fill', r.x-1, r.y-1, r.w, r.h)
	love.graphics.setColor(1,1,1)
	love.graphics.rectangle('line', r.x-1, r.y-1, r.w, r.h)
end
mazer-03.png
mazer-03.png (9.41 KiB) Viewed 1241 times
Attachments
mazer-03.love
(2.63 KiB) Downloaded 65 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 51 guests