Help on a room generation system

  1. What do you want to achieve? Keep it simple and clear!
    I want to make a proper modular room generation system for my lethal company like game
  2. What is the issue? Include screenshots / videos if possible!
    basically, the module generates doors and openings to other rooms that are occupying a provided space in a table. The issue is that sometimes it doesn’t generate a doorway, completely blocking off rooms and even the entrance. Also, sometimes doorways are opened when there is no room there.
  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    Ive tried changing the code logic several times and rewriting it but i couldn’t find any useful solutions.
local module = {}

local incriment = 28
local rooms = game.ServerStorage.Rooms
local roomStorage = workspace.Game.Rooms

local occupiedSpaces = {}
local border = -2031.5

function module:Clear()
	roomStorage:ClearAllChildren()
	table.clear(occupiedSpaces)
end

local function getIndexFromValue(t, value)
	for i, v in pairs(t) do
		if v == value then
			return i
		end
	end
end

function open(part:BasePart,bool:boolean)
	if part then
		local e ={
			[true] = 1,
			[false] = 0
		}
		part.Transparency = e[bool]
		part.CanCollide = bool
		part.CanTouch = bool
		part.CanQuery = bool
	end
end


local function isOccupied(cframe)
	local position = cframe.Position
	for _, occupied in pairs(occupiedSpaces) do
		if (occupied.Position - position).Magnitude < 1 then 
			for i,v in pairs(workspace.Game.Rooms:GetChildren()) do
				if v.PrimaryPart.Position == position then
					return true
				end
			end
		end
	end
	return false
end

function module:Generate(worldLimit:number)

	local types = {"Factory"}
	local randomType = types[math.random(1, #types)]

	local seedInfo = {}
	table.insert(seedInfo, getIndexFromValue(types, randomType))
	table.insert(seedInfo, worldLimit)

	local startingCFrame = workspace.Game.ImportantGameStuff.FirstGenerationPoint.CFrame
	local offsets = {
		["Left"] = Vector3.new(incriment, 0, 0),
		["Right"] = Vector3.new(-incriment, 0, 0),
		["Front"] = Vector3.new(0, 0, -incriment),
		["Back"] = Vector3.new(0, 0, incriment),
	}

	local opposites = {
		["Left"] = "Right",
		["Right"] = "Left",
		["Front"] = "Back",
		["Back"] = "Front",
	}

	local function createRoom(cframe, firstRoom)
		local validChecks = {"Front", "Left", "Back", "Right"}

		if isOccupied(cframe) then
			return
		end

		local gRooms = rooms:FindFirstChild(randomType)
		if not gRooms or #gRooms:GetChildren() == 0 then
			return
		end
		if #workspace.Game.Rooms:GetChildren() >= worldLimit then return end
		local selectedRoom = gRooms:GetChildren()[math.random(1, #gRooms:GetChildren())]:Clone()
		selectedRoom.Parent = roomStorage
		selectedRoom:PivotTo(cframe)
		if #workspace.Game.Rooms:GetChildren() < worldLimit then table.insert(occupiedSpaces, cframe) end
		if selectedRoom:FindFirstChild("Nodes") then
			for i,v in pairs(selectedRoom:FindFirstChild("Nodes"):GetChildren()) do
				local n = game.ServerStorage.Node:Clone()
				n.Parent = workspace.Nodes
				n.CFrame = v.CFrame
				
			end
		end

		print("create " .. tostring(cframe.Position))

		local walls = {}
		for i, v in pairs(selectedRoom:GetChildren()) do
			if table.find(validChecks, v.Name) and v:IsA("Model") then
				table.insert(walls, v)
			end
		end

		local rWalls = {}
		for i = 1, #walls do
			local randomWall = walls[math.random(1, #walls)]
			table.insert(rWalls, randomWall)
			for i, g in pairs(walls) do
				if g == randomWall then
					table.remove(walls, i)
				end
			end
		end

		for i, v in pairs(rWalls) do
			wait()
			if v:FindFirstChild("DoorWay") then
				if firstRoom then
					if v.Name == "Back" then
						continue
					end
					--v:FindFirstChild("DoorWay"):Destroy()
					local offset = offsets[v.Name]
					local nCFrame = cframe * CFrame.new(offset)
					coroutine.wrap(function()
						createRoom(nCFrame, false)
					end)()
				else
					local offset = offsets[v.Name]
					local nCFrame = cframe * CFrame.new(offset)

					if nCFrame.Position.X <= border then
						return
					end

					if isOccupied(nCFrame) then
						if #workspace.Game.Rooms:GetChildren() >= worldLimit then return end
						coroutine.wrap(function()
							wait(0.3)
							if math.random(1, 5) == 1 then
								for i, d in pairs(workspace.Game.Rooms:GetChildren()) do
									if not d then return end
									if d.PrimaryPart.CFrame == nCFrame  then
										if not d then return end
										if not v then return end
								
										if d.Name == v.Parent.Name then
											if d:FindFirstChild(opposites[v.Name]) then
												for i,e in pairs(d:FindFirstChild(opposites[v.Name]):GetChildren()) do
													if not e:IsA("BasePart") then return end
													open(e,true)
												end
												for i,e in pairs(v:FindFirstChild(opposites[v.Name]):GetChildren()) do
													if not e:IsA("BasePart") then return end
													open(e,true)
												end
											else
												warn("not found!")
												for i,e in pairs(v:FindFirstChild(opposites[v.Name]):GetChildren()) do
													if not e:IsA("BasePart") then return end
													open(e,false)
												end
											end
										else
											if d:FindFirstChild(opposites[v.Name]) and not d:FindFirstChild(opposites[v.Name]):FindFirstChild("DoorWay")then
												open(d:FindFirstChild(opposites[v.Name]):FindFirstChild("DoorWay"),true)
												open(v:FindFirstChild("DoorWay"),true)
												
											else
												warn("no opposite")
												open(v:FindFirstChild("DoorWay"),false)
											end
										end
									end
								end
							else
								for i, d in pairs(workspace.Game.Rooms:GetChildren()) do
									if d.PrimaryPart.CFrame == nCFrame then
										if not d then return end
										if d:FindFirstChild(opposites[v.Name]) and d:FindFirstChild(opposites[v.Name]):FindFirstChild("DoorWay") then
											open(d:FindFirstChild(opposites[v.Name]):FindFirstChild("DoorWay"),true)
											open(v:FindFirstChild("DoorWay"),true)
										else
											warn("no door for this guy")
											open(v:FindFirstChild("DoorWay"),false)
										end
									end
								end
							end
						end)()
					else
						if #workspace.Game.Rooms:GetChildren() < worldLimit then
							--v:FindFirstChild("DoorWay"):Destroy()
							coroutine.wrap(function()
								wait()
								if #workspace.Game.Rooms:GetChildren() >= worldLimit then return end
								local r = createRoom(nCFrame, false)

								if not r then return end

								if not r:FindFirstChild(opposites[v.Name]) then return end
								if not r:FindFirstChild(opposites[v.Name]):FindFirstChild("DoorWay") then return end

								open(r:FindFirstChild(opposites[v.Name]:FindFirstChild("DoorWay")),true)
							end)()
						end
					end
				end
			else
				warn("god")
			end
		end

		return selectedRoom
	end

	local seed = ""

	createRoom(startingCFrame, true)

	table.insert(seedInfo, #roomStorage:GetChildren())
	for i, v in pairs(seedInfo) do
		if i == 1 then
			seed = seed .. v
		else
			seed = seed .. " _ " .. v
		end
	end

	return seed
end

return module

i figured it out, just had to reverse some of the values.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.