Rooms generate inside of eachother

I have this room generation system, it generates but some rooms generate inwards of their previous rooms generating chaos, I want to combat this but I have no idea how.

How it generates currently:


How it should generate:

Code:

local roomsLimit = 100
local GenerateDelay = true
local RoomsGenerating = 0
local CurrentNum = 1

-- Setups
local MaximumRooms = 100
local MinimumRooms = 1

local function RarityFunction(Rooms)
	local Weight = 0
	for _, Room in pairs(Rooms:GetChildren()) do
		Weight += Room.Rarity.Value
	end

	local randomWeight = Random.new():NextInteger(1, Weight)
	local currentWeight = 0
	local randomRoom = nil
	for i, Room in pairs(Rooms:GetChildren()) do
		currentWeight += Room.Rarity.Value
		if randomWeight <= currentWeight then
			randomRoom = Room
			break
		end
	end
	return randomRoom
end

local function FindClosestPart(part, range, NewRoom)
	local closestPart = nil
	local shortestDistance = math.huge

	for _, otherPart in ipairs(NewRoom.Connections:GetChildren()) do
		if otherPart ~= part then
			local distance = (otherPart.Position - part.Position).Magnitude
			if distance < shortestDistance then
				closestPart = otherPart
				shortestDistance = distance
			end
		end
	end

	return closestPart
end

local function CanFit(newRoom, targetPart)
	local newRoomParts = newRoom:GetDescendants()
	for _, part in ipairs(newRoomParts) do
		if part:IsA("BasePart") then
			local collisionFound = false
			if part:IsDescendantOf(newRoom) then
				for _, existingPart in ipairs(part:GetTouchingParts()) do
					if not existingPart:IsDescendantOf(newRoom) then
						collisionFound = true
						break
					end
				end
				if not collisionFound then
					return true
				end
			end
		end
	end
	return false
end

local function GenerateRoom(PrevRoom)
	if RoomsGenerating >= roomsLimit then
		return
	end

	repeat
		task.wait()
	until PrevRoom

	for i, v in pairs(PrevRoom.Connections:GetChildren()) do
		task.wait(1)
		PrevRoom.PrimaryPart = v
		local randomRoom = RarityFunction(workspace.GasPipeRooms)
		if randomRoom then
			local newRoom = randomRoom:Clone()
			local SelectedPoints = newRoom.Connections:GetChildren()
			local points = PrevRoom.Connections:GetChildren()
			local SelectedPoint = points[math.random(1, #points)]

			local closestPoint = FindClosestPart(v, 2, newRoom)

			while not CanFit(newRoom, closestPoint) do
				randomRoom = RarityFunction(workspace.GasPipeRooms)
				if randomRoom then
					newRoom = randomRoom:Clone()
					SelectedPoints = newRoom.Connections:GetChildren()
					SelectedPoint = points[math.random(1, #points)]
					closestPoint = FindClosestPart(v, 2, newRoom)
				else
					local deadEnd = script.DeadEnd:Clone()
					deadEnd.Parent = workspace.GeneratedRoomsFolder.GeneratedGasPipeRooms
					deadEnd:PivotTo(PrevRoom.PrimaryPart.CFrame)
					return
				end
			end

			newRoom.PrimaryPart = closestPoint
			newRoom.Parent = game.Workspace.GeneratedRoomsFolder.GeneratedGasPipeRooms
			newRoom:PivotTo(SelectedPoint.CFrame)
			local newRoomCFrame = newRoom:GetPivot()
			local rotationCFrame = CFrame.Angles(0, 0, 0)
			if closestPoint.Orientation == SelectedPoint.Orientation then
				newRoom:PivotTo(newRoomCFrame * rotationCFrame)
			end
			RoomsGenerating += 1
			if RoomsGenerating >= roomsLimit then
				return
			end
			
			SelectedPoint:Destroy()
			closestPoint:Destroy()
			newRoom.PrimaryPart = nil
			PrevRoom.PrimaryPart = nil
			PrevRoom = newRoom
			GenerateRoom(PrevRoom)
		end
	end
end

local PrevRoom1 = game.Workspace.ConnectorRoom.Connector
GenerateRoom(PrevRoom1)

Basically it should generate like a grid, no parts generating inward, I added a CanFit() function but I dont think it works, anyone has any ideas on how to fix this?

Try putting prints in before if statements to see what the variables are that you are checking.
You can find out which variables don’t have the values you expect and troubleshoot back to what sets those variables.

1 Like

Using collision detection and rejection sampling is just the wrong way to go about this. The performance of this will be very bad and get worse as the structure gets larger. You should consider a purely geometric approach; compute or author simple metadata about each room module, and build the structure as a graph.There should be no need to do part-based collision checks, you know at authoring time how big things are, where doors are, etc.

2 Likes