Simple Random Tile Generation

I want to achieve a “Random Platform/Room Generation System” that when the game starts, there are platforms being randomly generated inside the empty world in the following pattern:

Each platform is a clone of the Template Part, located in ReplicatedStorage.Platforms.Default. Each platform is 20x20 studs.

There is a main room, ranging from 3x3 up to 6x6 platforms. There are several paths / halls that connect to other rooms. Some Paths connect to each other as well, like shown in the picture below.

Here is a near perfect example of the script I’m looking for:

The main room is the green one, while all the subrooms are the blue ones. No doors, no walls, just the floor platforms. (The color of the platform is not important, I just named them to showcase the rooms in the picture)

[EDIT]
Here is a more accurate image of the generation I’m looking for (Each tile is 20x20 studs):

The rooms in this picture could be bigger though.

If anybody could help me with this, that would be extremely helpful! I appreciate every answer! If you have any questions, ask below and I will respond as fast as possible. Thank you for reading!

1 Like

Are the halls 20x20 platforms too?

Yes, all rooms are made out of 20x20 stud platforms. I’m sorry because the example image I linked in my post was handmade therefore it wasn’t exactly accurate (The size of the platforms). Thank you for your reply!

Just so you know, I’m trying to program it and as soon as I’m done I’ll send you how my script turned out.

Thank you so much! I really appreciate it, I’ve been trying for 3 hours and I didn’t get it to work

Finally I finished it, here it is:

local RS = game:GetService("ReplicatedStorage")
local Platforms = RS:WaitForChild("Platforms")
local DefaultPlatform = Platforms:WaitForChild("Default")

local PlatformsFolder = Instance.new("Folder", workspace)
PlatformsFolder.Name = "Platforms"

local MainRoomFolder = Instance.new("Folder", PlatformsFolder)
MainRoomFolder.Name = "MainRoom"
local RoomsFolder = Instance.new("Folder", PlatformsFolder)
RoomsFolder.Name = "Rooms"
local HallsFolder = Instance.new("Folder", PlatformsFolder)
HallsFolder.Name = "Halls"

-- In RoomInfo, you can adjust somethings on generation
local RoomInfo = {
	["RoomNumber"] = math.random(7, 10), -- How many rooms are there
	["MainRoomSizeX"] = math.random(3,6), -- The X number of platforms that MainRoom will have
	["MainRoomSizeZ"] = math.random(3,6), -- The Y number of platforms that MainRoom will have
	["InitialPosition"] = Vector3.new(0,10,0), -- The initial position of it (the first main room platform will spawn at this coordinates)
	["HallsMinSize"] = 3, -- The min size that a corridor must have
	["HallsMaxSize"] = 6, -- The max size that a corridor must have
}

local function SetBridgeables(parent, sizeX)
	
	for _, Platform in pairs(parent:GetChildren()) do
		
		Platform:SetAttribute("BridgeableUp", true)
		Platform:SetAttribute("BridgeableRight", true)
		Platform:SetAttribute("BridgeableLeft", true)
		Platform:SetAttribute("BridgeableDown", true)
		
		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
		RayParams.FilterType = Enum.RaycastFilterType.Include
		
		local RaycastTest1 = workspace:Raycast(Platform.Position + Vector3.new(0, 100, 20), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest2 = workspace:Raycast(Platform.Position + Vector3.new(-20, 100, 0), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest3 = workspace:Raycast(Platform.Position + Vector3.new(20, 100, 0), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest4 = workspace:Raycast(Platform.Position + Vector3.new(0, 100, -20), Vector3.new(0,-10000,0), RayParams)
		
		if RaycastTest1 then
			Platform:SetAttribute("BridgeableUp", false)
		end

		if RaycastTest2 then
			Platform:SetAttribute("BridgeableRight", false)
		end

		if RaycastTest3 then
			Platform:SetAttribute("BridgeableLeft", false)
		end

		if RaycastTest4 then
			Platform:SetAttribute("BridgeableDown", false)
		end
		
	end
	
end

local function DesignAHallPlan(size, initialPosition, direction, timesTrying)
	
	local hall = {}
	local nowPosition = initialPosition
	
	local myDirection = direction
	
	for i = 1,size,1 do
		
		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
		RayParams.FilterType = Enum.RaycastFilterType.Include

		local RaycastTest = workspace:Raycast(nowPosition + (myDirection * 20) + Vector3.new(0,100,0), Vector3.new(0,-10000,0), RayParams)
		
		if not RaycastTest then
			nowPosition = nowPosition + (myDirection * 20)
			table.insert(hall, nowPosition)
			
			if math.random(1,4) == 1 and i > 2 then
				if myDirection.X ~= 0 then
					if math.random(1,2) == 1 then
						myDirection = Vector3.new(0,0,1)
					else
						myDirection = Vector3.new(0,0,-1)
					end
				else
					if math.random(1,2) == 1 then
						myDirection = Vector3.new(1,0,0)
					else
						myDirection = Vector3.new(-1,0,0)
					end
				end
			end
			
		else
			if not timesTrying then
				return DesignAHallPlan(size, initialPosition, direction, 1)
			else
				if timesTrying > 20 then
					return nil
				else
					return DesignAHallPlan(size, initialPosition, direction, timesTrying + 1)
				end
			end
		end
		
	end
	
	return hall, myDirection
	
end

local function GenerateRoom(lastBridge, direction, parent, timesTrying)
	
	local myDirection = direction
	
	local SizeX = math.random(4,7)
	local SizeZ = math.random(4,7)
	
	local InitialPosition = lastBridge.Position + (myDirection * 20)
	
	local preventMultiplier = 1
	
	if direction == Vector3.new(-1,0,0) or direction == Vector3.new(0,0,-1) then
		preventMultiplier = -1
	end
	
	for x = 1, SizeX, 1 do
		
		for z = 1, SizeZ, 1 do
			
			local RayParams = RaycastParams.new()
			RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
			RayParams.FilterType = Enum.RaycastFilterType.Include

			local RaycastTest = workspace:Raycast(InitialPosition + Vector3.new((x-1)*20*preventMultiplier,0,(z-1)*20*preventMultiplier) + Vector3.new(0,100,0), Vector3.new(0,-10000,0), RayParams)
			
			if RaycastTest then
				
				for _, v in pairs(parent:GetChildren()) do

					game:GetService("Debris"):AddItem(v, 0)

				end
				
				if not timesTrying then
					return GenerateRoom(lastBridge, direction, parent, 1)
				else
					if timesTrying > 20 then
						return nil
					else
						return GenerateRoom(lastBridge, direction, parent, timesTrying+1)
					end
				end
				
			end
			
			local Platform = DefaultPlatform:Clone()
			local PlatformID = x + ((z-1)*SizeX)
			
			Platform.Parent = parent
			Platform.Name = "Platform"..PlatformID
			Platform.Color = Color3.fromRGB(49, 176, 255)
			Platform.Position = InitialPosition + Vector3.new((x-1)*20*preventMultiplier,0,(z-1)*20*preventMultiplier)
			
		end
		
	end
	
	return SizeX
	
end

local function GenerateRoomProcess(roomFolder, roomType)
	
	if roomType == "FirstRoom" then
		
		local BridgeSize = math.random(RoomInfo["HallsMinSize"],RoomInfo["HallsMaxSize"])
		local BridgeablesParts = {}

		for _, v in pairs(MainRoomFolder:GetChildren()) do

			local canInsert = false

			if v:GetAttribute("BridgeableUp") then
				canInsert = true
			elseif v:GetAttribute("BridgeableLeft") then
				canInsert = true
			elseif v:GetAttribute("BridgeableRight") then
				canInsert = true
			elseif v:GetAttribute("BridgeableDown") then
				canInsert = true
			end

			if canInsert then
				table.insert(BridgeablesParts, v)
			end

		end

		local myPart = BridgeablesParts[math.random(1,#BridgeablesParts)]
		local Directions = {}

		if myPart:GetAttribute("BridgeableUp") then
			table.insert(Directions, "Up")
		end
		if myPart:GetAttribute("BridgeableLeft") then
			table.insert(Directions, "Left")
		end
		if myPart:GetAttribute("BridgeableRight") then
			table.insert(Directions, "Right")
		end
		if myPart:GetAttribute("BridgeableDown") then
			table.insert(Directions, "Down")
		end

		local myDirection = Directions[math.random(1, #Directions)]

		myPart:SetAttribute("Bridgeable"..myDirection, false)

		local vectorDirection = Vector3.new(0,0,0)

		if myDirection == "Up" then
			vectorDirection = Vector3.new(0,0,1)
		elseif myDirection == "Left" then
			vectorDirection = Vector3.new(1,0,0)
		elseif myDirection == "Right" then
			vectorDirection = Vector3.new(-1,0,0)
		elseif myDirection == "Down" then
			vectorDirection = Vector3.new(0,0,-1)
		end

		local HallPlan = DesignAHallPlan(BridgeSize, myPart.Position, vectorDirection)
		local LastBridge = nil
		local BridgeParts = {}
		
		if not HallPlan then
			myPart:SetAttribute("Bridgeable"..myDirection, true)
			return GenerateRoomProcess(roomFolder, roomType)
		end

		for i, v in pairs(HallPlan) do

			local Platform = DefaultPlatform:Clone()
			Platform.Parent = HallsFolder
			Platform.Name = "Hall"..i
			Platform.Position = v
			Platform.Color = Color3.fromRGB(80,80,80)

			table.insert(BridgeParts, Platform)

			if i == #HallPlan then

				LastBridge = Platform

			end

		end

		local RoomSizeX = GenerateRoom(LastBridge, vectorDirection, roomFolder)

		if RoomSizeX then
			
			SetBridgeables(roomFolder, RoomSizeX)
			
			for _, v in pairs(roomFolder:GetDescendants()) do

				local everythingFine = true

				local RayParams = RaycastParams.new()
				RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
				RayParams.FilterType = Enum.RaycastFilterType.Include

				local UpRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,20), Vector3.new(0,-10000,0), RayParams)
				local RightRaycastTest = workspace:Raycast(v.Position + Vector3.new(-20,100,0), Vector3.new(0,-10000,0), RayParams)
				local LeftRaycastTest = workspace:Raycast(v.Position + Vector3.new(20,100,0), Vector3.new(0,-10000,0), RayParams)
				local DownRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,-20), Vector3.new(0,-10000,0), RayParams)

				if UpRaycastTest and UpRaycastTest.Instance.Parent ~= roomFolder and UpRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if LeftRaycastTest and LeftRaycastTest.Instance.Parent ~= roomFolder and LeftRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if RightRaycastTest and RightRaycastTest.Instance.Parent ~= roomFolder and RightRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if DownRaycastTest and DownRaycastTest.Instance.Parent ~= roomFolder and DownRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if not everythingFine then
					myPart:SetAttribute("Bridgeable"..myDirection, true)

					for _, v in pairs(BridgeParts) do
						game:GetService("Debris"):AddItem(v, 0)
					end

					return GenerateRoomProcess(roomFolder, roomType)
				end

			end
			
		else
			myPart:SetAttribute("Bridgeable"..myDirection, true)

			for _, v in pairs(BridgeParts) do
				game:GetService("Debris"):AddItem(v, 0)
			end

			return GenerateRoomProcess(roomFolder, roomType)

		end
		
	else
		
		local BridgeSize = math.random(RoomInfo["HallsMinSize"],RoomInfo["HallsMaxSize"])
		local BridgeablesParts = {}

		for _, v in pairs(MainRoomFolder:GetDescendants()) do

			local canInsert = false

			if v:GetAttribute("BridgeableUp") then
				canInsert = true
			elseif v:GetAttribute("BridgeableLeft") then
				canInsert = true
			elseif v:GetAttribute("BridgeableRight") then
				canInsert = true
			elseif v:GetAttribute("BridgeableDown") then
				canInsert = true
			end

			if canInsert then
				table.insert(BridgeablesParts, v)
			end

		end
		
		if math.random(1,15) == 1 then
			for _, v in pairs(RoomsFolder:GetDescendants()) do

				local canInsert = false

				if v:GetAttribute("BridgeableUp") then
					canInsert = true
				elseif v:GetAttribute("BridgeableLeft") then
					canInsert = true
				elseif v:GetAttribute("BridgeableRight") then
					canInsert = true
				elseif v:GetAttribute("BridgeableDown") then
					canInsert = true
				end

				if canInsert then
					table.insert(BridgeablesParts, v)
				end

			end
		end
		
		local myPart = BridgeablesParts[math.random(1,#BridgeablesParts)]
		local Directions = {}

		if myPart:GetAttribute("BridgeableUp") then
			table.insert(Directions, "Up")
		end
		if myPart:GetAttribute("BridgeableLeft") then
			table.insert(Directions, "Left")
		end
		if myPart:GetAttribute("BridgeableRight") then
			table.insert(Directions, "Right")
		end
		if myPart:GetAttribute("BridgeableDown") then
			table.insert(Directions, "Down")
		end

		local myDirection = Directions[math.random(1, #Directions)]
		
		myPart:SetAttribute("Bridgeable"..myDirection, false)

		local vectorDirection = Vector3.new(0,0,0)

		if myDirection == "Up" then
			vectorDirection = Vector3.new(0,0,1)
		elseif myDirection == "Left" then
			vectorDirection = Vector3.new(1,0,0)
		elseif myDirection == "Right" then
			vectorDirection = Vector3.new(-1,0,0)
		elseif myDirection == "Down" then
			vectorDirection = Vector3.new(0,0,-1)
		end
		
		local HallPlan, finalDirection = DesignAHallPlan(BridgeSize, myPart.Position, vectorDirection)
		local LastBridge = nil
		local BridgeParts = {}
		
		if not HallPlan then
			myPart:SetAttribute("Bridgeable"..myDirection, true)
			return GenerateRoomProcess(roomFolder, roomType)
		end
		
		for i, v in pairs(HallPlan) do

			local Platform = DefaultPlatform:Clone()
			Platform.Parent = HallsFolder
			Platform.Name = "Hall"..i
			Platform.Position = v
			Platform.Color = Color3.fromRGB(80,80,80)

			table.insert(BridgeParts, Platform)

			if i == #HallPlan then

				LastBridge = Platform

			end

		end

		local RoomSizeX = GenerateRoom(LastBridge, finalDirection, roomFolder)

		if RoomSizeX then
			
			SetBridgeables(roomFolder, RoomSizeX)
			
			for _, v in pairs(roomFolder:GetDescendants()) do
				
				local everythingFine = true
				
				local RayParams = RaycastParams.new()
				RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
				RayParams.FilterType = Enum.RaycastFilterType.Include
				
				local UpRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,20), Vector3.new(0,-10000,0), RayParams)
				local RightRaycastTest = workspace:Raycast(v.Position + Vector3.new(-20,100,0), Vector3.new(0,-10000,0), RayParams)
				local LeftRaycastTest = workspace:Raycast(v.Position + Vector3.new(20,100,0), Vector3.new(0,-10000,0), RayParams)
				local DownRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,-20), Vector3.new(0,-10000,0), RayParams)
				
				if UpRaycastTest and UpRaycastTest.Instance.Parent ~= roomFolder and UpRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end
				
				if LeftRaycastTest and LeftRaycastTest.Instance.Parent ~= roomFolder and LeftRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end
				
				if RightRaycastTest and RightRaycastTest.Instance.Parent ~= roomFolder and RightRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end
				
				if DownRaycastTest and DownRaycastTest.Instance.Parent ~= roomFolder and DownRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end
				
				if not everythingFine then
					myPart:SetAttribute("Bridgeable"..myDirection, true)

					for _, v in pairs(BridgeParts) do
						game:GetService("Debris"):AddItem(v, 0)
					end

					return GenerateRoomProcess(roomFolder, roomType)
				end
				
			end
			
		else
			
			myPart:SetAttribute("Bridgeable"..myDirection, true)

			for _, v in pairs(BridgeParts) do
				game:GetService("Debris"):AddItem(v, 0)
			end

			return GenerateRoomProcess(roomFolder, roomType)

		end
		
	end
	
end

for x = 1, RoomInfo["MainRoomSizeX"], 1 do
	
	for z = 1, RoomInfo["MainRoomSizeZ"], 1 do
		
		local Platform = DefaultPlatform:Clone()
		local PlatformID = x + ((z-1)*RoomInfo["MainRoomSizeX"])
		Platform.Parent = MainRoomFolder
		Platform.Name = "Platform"..PlatformID
		Platform.Color = Color3.fromRGB(0, 255, 0)
		Platform.Position = RoomInfo["InitialPosition"] + Vector3.new((x-1)*20,0,(z-1)*20)
		
	end
	
end

SetBridgeables(MainRoomFolder, RoomInfo["MainRoomSizeX"])

while #RoomsFolder:GetChildren() < RoomInfo["RoomNumber"] do
	
	local NewRoom = Instance.new("Folder", RoomsFolder)
	NewRoom.Name = "Room"..#RoomsFolder:GetChildren()
	
	if #RoomsFolder:GetChildren() == 1 then
		
		GenerateRoomProcess(NewRoom, "FirstRoom")
		
	else
		
		GenerateRoomProcess(NewRoom, "Room")
		
	end
	
end

:arrow_up: :arrow_up: :arrow_up:
Put a script with this code in ServerScriptService


I would explain it but I’m too lazy now. If you want me to explain it anyway I will, just reply this post!

NOTE(S): It is take some time to load (principally when room number is high), so do a load screen or something like that. Another thing, if you want more than 15 rooms, I would recommend increasing the HallsMinSize and HallsMaxSize. It has some bugs.

Just tell me if you want me to adjust something.

2 Likes

A few months ago I made this, an autogenerated maze for a friend

500 rooms (with 20-30 objects) and 60 fps :money_mouth_face:, with @Y4rok

Basically it is this:

  • I place the center.
  • I choose a random room, select a door and place and rotate the room according to the door, if the room doesn’t work, I choose another one and repeat.
  • I add all the doors to a list, the list pulls a door, checks that there is nothing in front of it and tries to place a room in front choosing a random door, if all are discarded, another room is placed and tried again, also verifying that it does not overlap another room.
  • If no room fits, the door is set to “locked”, my friend had a door with wood.
  • Repeat everything until you have the number of rooms you want.

Another code is responsible for verifying and eliminating duplicate doors and thus connecting the rooms, result with something extra:

So, you could do the same, if you want long hallways you could, instead of directly placing a room, create a hallway with a random distance.

1 Like

Bro destroyed my reply :skull:

Anyway, I was reading his post again and I notice that he is asking that some platforms may be connected with others naturally (i mean, platforms with more than 1 thing connected). You have any idea how to do that? Because I’m thinking and can’t find any good solution.

The same thing I did but without walls, just have to adjust the doors to be “connected”.
If the part that simulates the door is very close it will overlap, so you just have to play and keep everything within its limits, it is literally a puzzle generator

Pff, nah, it’s fine, your answer is good, I just gave an idea.
Actually, could I give a simple code, one moment (like a hour lol)

1 Like

So, here we go:


More simply, each room has:
image

  • Collision: simple representation with parts of the boundaries of the room.
  • Decoration: everything the room includes.
  • Doors: parts that represent doors, all doors must face outside the room.
    Captura de pantalla 2024-12-10 203310

The doors must be exactly on the edge and at floor height

Here my script
--! strict
--		Settings		--
local MaxRooms = 10
local Time = 0.1

--		Instances		--
local Rooms = game:GetService("ServerStorage").Rooms

--		Variables		--
local OP = OverlapParams.new()
OP.FilterType = Enum.RaycastFilterType.Include
OP.BruteForceAllSlow = true
OP.MaxParts = 1
OP:AddToFilter(workspace.Center.Collision)

local random = Random.new()

--		Typecheck		--
type RoomModel = Model&{
	Doors: Model,
	Decoration: Model,
	Collision: Model,
}
type RoomData = {
	Objects: {Base: RoomData, Decoration: Model&{Center: BasePart}},
	CollisionPack: CollisionPack,
}
type CollisionPack = Model&{Doors: Model, Collision: Model, Center: BasePart}


--		Create rooms data		--
local RoomsData: {RoomData} = {}
for n, Room: RoomModel in pairs(Rooms:GetChildren()) do
	local Data: RoomData = {} :: RoomData
	Data.Objects = {
		["Base"] = Room,
		["Decoration"] = Room.Decoration::any,
	}
	Room.Decoration.Name = Room.Name
	Room.Doors:Clone().Parent = Data.Objects.Decoration --> extra stuff
	
	--		Collision pack		--
	Data.CollisionPack = Instance.new("Model")::any
	Data.CollisionPack.Name = Room.Name
	Room.Doors.Parent = Data.CollisionPack
	Room.Collision.Parent = Data.CollisionPack
	
	--		Center block		--
	local Center = script.Center:Clone()
	Center.CFrame = Room:GetPivot()
	Center:Clone().Parent = Data.CollisionPack
	Center.Parent = Data.Objects.Decoration
	
	--		Primary parts		--
	Data.Objects.Decoration.PrimaryPart = Center
	Data.CollisionPack:SetAttribute("RoomIndex", #RoomsData + 1)
	table.insert(RoomsData, Data)
end



--		Start loop		--
local DoorLoop, RoomsFrames, ShuffleRooms = {workspace.Center.Door}, {}, table.clone(RoomsData)
while #DoorLoop > 0 and #RoomsFrames < MaxRooms and task.wait() do --> extra time or lag
	local Current = table.remove(DoorLoop, 1) :: BasePart
	random:Shuffle(ShuffleRooms)
	
	--		Next door		--
	for _, Room: RoomData in pairs(ShuffleRooms) do
		local pack = Room.CollisionPack
		pack.Parent = workspace
		
		--		Check		--
		local Success: boolean = nil
		for _, Door: BasePart in pairs(pack.Doors:GetChildren()) do
			--		Place door		--
			pack.PrimaryPart = Door
			pack:PivotTo(Current.CFrame * CFrame.Angles(0, math.pi, 0))

			--		Check collisions		--
			local Collisions: boolean? = nil
			for _, CollisionPart in pairs(pack.Collision:GetChildren()) do
				Collisions = (#workspace:GetPartsInPart(CollisionPart, OP) > 0)
				if Collisions then		break		end
			end
			if Collisions then		continue			end
			
			--		Create rooms if not collisions
			local cloneRoom = pack:Clone() :: CollisionPack
			cloneRoom.PrimaryPart = cloneRoom.Center
			cloneRoom.Parent = workspace
			OP:AddToFilter(cloneRoom.Collision)
			table.insert(RoomsFrames, cloneRoom)

			--		Add to the list		--
			for _, v in pairs(cloneRoom.Doors:GetChildren()) do
				if v.CFrame ~= Door.CFrame then		table.insert(DoorLoop, v)		end
			end
			Success = true
			break
		end
		pack.Parent = nil

		--		Next door or reapeat?		--
		if Success then		task.wait(Time) break		end
	end
end
warn("GENERATE ROOMS")


--		Create rooms		--
for _, v: CollisionPack in pairs(RoomsFrames) do
	local Index = v:GetAttribute("RoomIndex")
	local data: RoomData = RoomsData[Index]
	
	--		Create data and remove old		--
	local RealRoom = data.Objects.Decoration:Clone()
	RealRoom.PrimaryPart = RealRoom.Center
	RealRoom:PivotTo(v.Center.CFrame)
	RealRoom.Parent = workspace.Rooms
	v:Destroy()
	
	RealRoom.Doors:PivotTo(RealRoom.Doors:GetPivot() + Vector3.yAxis) --> extra stuff
	task.wait(Time)
end
workspace.Center.Collision:Destroy()

Result: 10 rooms

To this you can add probability and whatever you need, with hallways they could simply be long rooms more likely to appear.


Why do rooms need collision? It is more precise and easier to know if two rooms collide.
simple maze.rbxl (52,6 KB)

2 Likes

bro, so cool!

Can you just explain why you put type something = {} sometimes and, after variables you put “:”? I have saw this multiple times and don’t know what they mean.

In some lines you put “::”, for example Data.CollisionPack = Instance.new("Model")::any. What does this “::” mean?

It is for type checking, so I don’t misspell any property or descendant object, and the studio tells me if something is misspelled.


:: type is used to “override” a type, for example:

local N: number = tonumber("20")

image

tonumber can return nil, so number?, the “?” means the given value could be nil.

This is a warning, it doesn’t affect the script, but it is annoying, so I can “silence” it this way:

local N: number = tonumber("20") :: number

I basically tell it to ignore the type and let the variable behave like a number, I can also do it like this

local N = tonumber("20") :: number
local N: number = tonumber("20") :: any --> or this

are the same

1 Like

Thanks bro! You make it sound so more clear than Chat-GPT :grin: :+1:

1 Like

I’m speechless right now, the amount of time it would take me to not only code this but understand it would take days, Thank you so much for that! I really needed that since I couldn’t do it myself, I tried everything but didn’t really got it to work without any bugs, now I’m trying to add walls and a roof that are placed around each room and hallway, literally just a part, no model and nothing fancy. I’m trying my best to do it myself because you already did a lot, Tysm again! How long have you been coding to achieve that??

1 Like

I don’t remember well. I had to stop a lot of times (and one time Roblox Studio just started to update while I was working on this and I lost 5%, lol). I would guess 3 hours or smth around that.

1 Like

If you want a hint to make walls, use the “Bridgeable Up/Down/Left/Right” attributes I created. If it is setted to true, it means that it doesn’t have anything on its side and you can create a wall there.

1 Like

I tried creating walls and it works for all subrooms (except if there are more than 1 hallway connect to one room) but not the mainroom and the hallways. Is there any way you could help me? (After that I would also generate a roof, which basically is the exact same 20x20 platform above every other platform, but here is the code I tried:

local RS = game:GetService("ReplicatedStorage")
local Platforms = RS:WaitForChild("Platforms")
local DefaultPlatform = Platforms:WaitForChild("Default")

local PlatformsFolder = Instance.new("Folder", workspace)
PlatformsFolder.Name = "Platforms"

local MainRoomFolder = Instance.new("Folder", PlatformsFolder)
MainRoomFolder.Name = "MainRoom"
local RoomsFolder = Instance.new("Folder", PlatformsFolder)
RoomsFolder.Name = "Rooms"
local HallsFolder = Instance.new("Folder", PlatformsFolder)
HallsFolder.Name = "Halls"
local WallsFolder = Instance.new("Folder", workspace)
WallsFolder.Name = "Walls"

-- In RoomInfo, you can adjust somethings on generation
local RoomInfo = {
	["RoomNumber"] = math.random(7, 10), -- How many rooms are there
	["MainRoomSizeX"] = math.random(3,6), -- The X number of platforms that MainRoom will have
	["MainRoomSizeZ"] = math.random(3,6), -- The Y number of platforms that MainRoom will have
	["InitialPosition"] = Vector3.new(0,0,0), -- The initial position of it (the first main room platform will spawn at this coordinates)
	["HallsMinSize"] = 3, -- The min size that a corridor must have
	["HallsMaxSize"] = 6, -- The max size that a corridor must have
}

local function SetBridgeables(parent, sizeX)

	for _, Platform: Part in pairs(parent:GetChildren()) do

		Platform:SetAttribute("BridgeableUp", true)
		Platform:SetAttribute("BridgeableRight", true)
		Platform:SetAttribute("BridgeableLeft", true)
		Platform:SetAttribute("BridgeableDown", true)

		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
		RayParams.FilterType = Enum.RaycastFilterType.Include

		local RaycastTest1 = workspace:Raycast(Platform.Position + Vector3.new(0, 100, 20), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest2 = workspace:Raycast(Platform.Position + Vector3.new(-20, 100, 0), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest3 = workspace:Raycast(Platform.Position + Vector3.new(20, 100, 0), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest4 = workspace:Raycast(Platform.Position + Vector3.new(0, 100, -20), Vector3.new(0,-10000,0), RayParams)

		if RaycastTest1 then
			Platform:SetAttribute("BridgeableUp", false)
		end

		if RaycastTest2 then
			Platform:SetAttribute("BridgeableRight", false)
		end

		if RaycastTest3 then
			Platform:SetAttribute("BridgeableLeft", false)
		end

		if RaycastTest4 then
			Platform:SetAttribute("BridgeableDown", false)
		end
		
		local Attributes = {
			BridgeableUp = Platform:GetAttribute("BridgeableUp"),
			BridgeableDown = Platform:GetAttribute("BridgeableDown"),
			BridgeableLeft = Platform:GetAttribute("BridgeableLeft"),
			BridgeableRight = Platform:GetAttribute("BridgeableRight"),
		}
		
		if Attributes.BridgeableUp then
			local Wall = Instance.new("Part", WallsFolder)
			Wall.Anchored = true
			Wall.Size = Vector3.new(20, 10, 1)
			Wall.Position = Platform.Position + Vector3.new(0,5,10)
			Wall.Color = Color3.new(0, 0.917647, 1)
			Platform.Destroying:Connect(function()
				Wall:Destroy()
			end)
		end
		if Attributes.BridgeableDown then
			local Wall = Instance.new("Part", WallsFolder)
			Wall.Anchored = true
			Wall.Size = Vector3.new(20, 10, 1)
			Wall.Position = Platform.Position + Vector3.new(0,5,-10)
			Wall.Color = Color3.new(0.0431373, 0.435294, 0)
			Platform.Destroying:Connect(function()
				Wall:Destroy()
			end)
		end
		if Attributes.BridgeableLeft then
			local Wall = Instance.new("Part", WallsFolder)
			Wall.Anchored = true
			Wall.Size = Vector3.new(1, 10, 20) 
			Wall.Rotation = Vector3.new(0,0,0) 
			Wall.Position = Platform.Position + Vector3.new(10,5,0)
			Wall.Color = Color3.new(1, 0, 0.0156863)
			Platform.Destroying:Connect(function()
				Wall:Destroy()
			end)
		end
		if Attributes.BridgeableRight then
			local Wall = Instance.new("Part", WallsFolder)
			Wall.Anchored = true
			Wall.Size = Vector3.new(1, 10, 20)
			Wall.Rotation = Vector3.new(0,0,0) 
			Wall.Position = Platform.Position + Vector3.new(-10,5,0)
			Wall.Color = Color3.new(0, 0.133333, 1)
			Platform.Destroying:Connect(function()
				Wall:Destroy()
			end)
		end
	end
end

local function DesignAHallPlan(size, initialPosition, direction, timesTrying)

	local hall = {}
	local nowPosition = initialPosition

	local myDirection = direction

	for i = 1,size,1 do

		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
		RayParams.FilterType = Enum.RaycastFilterType.Include

		local RaycastTest = workspace:Raycast(nowPosition + (myDirection * 20) + Vector3.new(0,100,0), Vector3.new(0,-10000,0), RayParams)

		if not RaycastTest then
			nowPosition = nowPosition + (myDirection * 20)
			table.insert(hall, nowPosition)

			if math.random(1,4) == 1 and i > 2 then
				if myDirection.X ~= 0 then
					if math.random(1,2) == 1 then
						myDirection = Vector3.new(0,0,1)
					else
						myDirection = Vector3.new(0,0,-1)
					end
				else
					if math.random(1,2) == 1 then
						myDirection = Vector3.new(1,0,0)
					else
						myDirection = Vector3.new(-1,0,0)
					end
				end
			end

		else
			if not timesTrying then
				return DesignAHallPlan(size, initialPosition, direction, 1)
			else
				if timesTrying > 20 then
					return nil
				else
					return DesignAHallPlan(size, initialPosition, direction, timesTrying + 1)
				end
			end
		end

	end

	return hall, myDirection

end

local function GenerateRoom(lastBridge, direction, parent, timesTrying)

	local myDirection = direction

	local SizeX = math.random(4,7)
	local SizeZ = math.random(4,7)

	local InitialPosition = lastBridge.Position + (myDirection * 20)

	local preventMultiplier = 1

	if direction == Vector3.new(-1,0,0) or direction == Vector3.new(0,0,-1) then
		preventMultiplier = -1
	end

	for x = 1, SizeX, 1 do

		for z = 1, SizeZ, 1 do

			local RayParams = RaycastParams.new()
			RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
			RayParams.FilterType = Enum.RaycastFilterType.Include

			local RaycastTest = workspace:Raycast(InitialPosition + Vector3.new((x-1)*20*preventMultiplier,0,(z-1)*20*preventMultiplier) + Vector3.new(0,100,0), Vector3.new(0,-10000,0), RayParams)

			if RaycastTest then

				for _, v in pairs(parent:GetChildren()) do

					game:GetService("Debris"):AddItem(v, 0)

				end

				if not timesTrying then
					return GenerateRoom(lastBridge, direction, parent, 1)
				else
					if timesTrying > 20 then
						return nil
					else
						return GenerateRoom(lastBridge, direction, parent, timesTrying+1)
					end
				end

			end

			local Platform = DefaultPlatform:Clone()
			local PlatformID = x + ((z-1)*SizeX)

			Platform.Parent = parent
			Platform.Name = "Platform"..PlatformID
			Platform.Color = Color3.fromRGB(49, 176, 255)
			Platform.Position = InitialPosition + Vector3.new((x-1)*20*preventMultiplier,0,(z-1)*20*preventMultiplier)

		end

	end

	return SizeX

end

local function GenerateRoomProcess(roomFolder, roomType)

	if roomType == "FirstRoom" then

		local BridgeSize = math.random(RoomInfo["HallsMinSize"],RoomInfo["HallsMaxSize"])
		local BridgeablesParts = {}

		for _, v in pairs(MainRoomFolder:GetChildren()) do

			local canInsert = false

			if v:GetAttribute("BridgeableUp") then
				canInsert = true
			elseif v:GetAttribute("BridgeableLeft") then
				canInsert = true
			elseif v:GetAttribute("BridgeableRight") then
				canInsert = true
			elseif v:GetAttribute("BridgeableDown") then
				canInsert = true
			end

			if canInsert then
				table.insert(BridgeablesParts, v)
			end

		end

		local myPart = BridgeablesParts[math.random(1,#BridgeablesParts)]
		local Directions = {}

		if myPart:GetAttribute("BridgeableUp") then
			table.insert(Directions, "Up")
		end
		if myPart:GetAttribute("BridgeableLeft") then
			table.insert(Directions, "Left")
		end
		if myPart:GetAttribute("BridgeableRight") then
			table.insert(Directions, "Right")
		end
		if myPart:GetAttribute("BridgeableDown") then
			table.insert(Directions, "Down")
		end

		local myDirection = Directions[math.random(1, #Directions)]

		myPart:SetAttribute("Bridgeable"..myDirection, false)

		local vectorDirection = Vector3.new(0,0,0)

		if myDirection == "Up" then
			vectorDirection = Vector3.new(0,0,1)
		elseif myDirection == "Left" then
			vectorDirection = Vector3.new(1,0,0)
		elseif myDirection == "Right" then
			vectorDirection = Vector3.new(-1,0,0)
		elseif myDirection == "Down" then
			vectorDirection = Vector3.new(0,0,-1)
		end

		local HallPlan = DesignAHallPlan(BridgeSize, myPart.Position, vectorDirection)
		local LastBridge = nil
		local BridgeParts = {}

		if not HallPlan then
			myPart:SetAttribute("Bridgeable"..myDirection, true)
			return GenerateRoomProcess(roomFolder, roomType)
		end

		for i, v in pairs(HallPlan) do

			local Platform = DefaultPlatform:Clone()
			Platform.Parent = HallsFolder
			Platform.Name = "Hall"..i
			Platform.Position = v
			Platform.Color = Color3.fromRGB(80,80,80)

			table.insert(BridgeParts, Platform)

			if i == #HallPlan then

				LastBridge = Platform

			end

		end

		local RoomSizeX = GenerateRoom(LastBridge, vectorDirection, roomFolder)

		if RoomSizeX then

			SetBridgeables(roomFolder, RoomSizeX)

			for _, v in pairs(roomFolder:GetDescendants()) do

				local everythingFine = true

				local RayParams = RaycastParams.new()
				RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
				RayParams.FilterType = Enum.RaycastFilterType.Include

				local UpRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,20), Vector3.new(0,-10000,0), RayParams)
				local RightRaycastTest = workspace:Raycast(v.Position + Vector3.new(-20,100,0), Vector3.new(0,-10000,0), RayParams)
				local LeftRaycastTest = workspace:Raycast(v.Position + Vector3.new(20,100,0), Vector3.new(0,-10000,0), RayParams)
				local DownRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,-20), Vector3.new(0,-10000,0), RayParams)

				if UpRaycastTest and UpRaycastTest.Instance.Parent ~= roomFolder and UpRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if LeftRaycastTest and LeftRaycastTest.Instance.Parent ~= roomFolder and LeftRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if RightRaycastTest and RightRaycastTest.Instance.Parent ~= roomFolder and RightRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if DownRaycastTest and DownRaycastTest.Instance.Parent ~= roomFolder and DownRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if not everythingFine then
					myPart:SetAttribute("Bridgeable"..myDirection, true)

					for _, v in pairs(BridgeParts) do
						game:GetService("Debris"):AddItem(v, 0)
					end

					return GenerateRoomProcess(roomFolder, roomType)
				end

			end

		else
			myPart:SetAttribute("Bridgeable"..myDirection, true)

			for _, v in pairs(BridgeParts) do
				game:GetService("Debris"):AddItem(v, 0)
			end

			return GenerateRoomProcess(roomFolder, roomType)

		end

	else

		local BridgeSize = math.random(RoomInfo["HallsMinSize"],RoomInfo["HallsMaxSize"])
		local BridgeablesParts = {}

		for _, v in pairs(MainRoomFolder:GetDescendants()) do

			local canInsert = false

			if v:GetAttribute("BridgeableUp") then
				canInsert = true
			elseif v:GetAttribute("BridgeableLeft") then
				canInsert = true
			elseif v:GetAttribute("BridgeableRight") then
				canInsert = true
			elseif v:GetAttribute("BridgeableDown") then
				canInsert = true
			end

			if canInsert then
				table.insert(BridgeablesParts, v)
			end

		end

		if math.random(1,15) == 1 then
			for _, v in pairs(RoomsFolder:GetDescendants()) do

				local canInsert = false

				if v:GetAttribute("BridgeableUp") then
					canInsert = true
				elseif v:GetAttribute("BridgeableLeft") then
					canInsert = true
				elseif v:GetAttribute("BridgeableRight") then
					canInsert = true
				elseif v:GetAttribute("BridgeableDown") then
					canInsert = true
				end

				if canInsert then
					table.insert(BridgeablesParts, v)
				end

			end
		end

		local myPart = BridgeablesParts[math.random(1,#BridgeablesParts)]
		local Directions = {}

		if myPart:GetAttribute("BridgeableUp") then
			table.insert(Directions, "Up")
		end
		if myPart:GetAttribute("BridgeableLeft") then
			table.insert(Directions, "Left")
		end
		if myPart:GetAttribute("BridgeableRight") then
			table.insert(Directions, "Right")
		end
		if myPart:GetAttribute("BridgeableDown") then
			table.insert(Directions, "Down")
		end

		local myDirection = Directions[math.random(1, #Directions)]

		myPart:SetAttribute("Bridgeable"..myDirection, false)

		local vectorDirection = Vector3.new(0,0,0)

		if myDirection == "Up" then
			vectorDirection = Vector3.new(0,0,1)
		elseif myDirection == "Left" then
			vectorDirection = Vector3.new(1,0,0)
		elseif myDirection == "Right" then
			vectorDirection = Vector3.new(-1,0,0)
		elseif myDirection == "Down" then
			vectorDirection = Vector3.new(0,0,-1)
		end

		local HallPlan, finalDirection = DesignAHallPlan(BridgeSize, myPart.Position, vectorDirection)
		local LastBridge = nil
		local BridgeParts = {}

		if not HallPlan then
			myPart:SetAttribute("Bridgeable"..myDirection, true)
			return GenerateRoomProcess(roomFolder, roomType)
		end

		for i, v in pairs(HallPlan) do

			local Platform = DefaultPlatform:Clone()
			Platform.Parent = HallsFolder
			Platform.Name = "Hall"..i
			Platform.Position = v
			Platform.Color = Color3.fromRGB(80,80,80)
			
			

			table.insert(BridgeParts, Platform)
			
			

			if i == #HallPlan then

				LastBridge = Platform

			end

		end

		local RoomSizeX = GenerateRoom(LastBridge, finalDirection, roomFolder)

		if RoomSizeX then

			SetBridgeables(roomFolder, RoomSizeX)

			for _, v in pairs(roomFolder:GetDescendants()) do

				local everythingFine = true

				local RayParams = RaycastParams.new()
				RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
				RayParams.FilterType = Enum.RaycastFilterType.Include

				local UpRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,20), Vector3.new(0,-10000,0), RayParams)
				local RightRaycastTest = workspace:Raycast(v.Position + Vector3.new(-20,100,0), Vector3.new(0,-10000,0), RayParams)
				local LeftRaycastTest = workspace:Raycast(v.Position + Vector3.new(20,100,0), Vector3.new(0,-10000,0), RayParams)
				local DownRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,-20), Vector3.new(0,-10000,0), RayParams)

				if UpRaycastTest and UpRaycastTest.Instance.Parent ~= roomFolder and UpRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if LeftRaycastTest and LeftRaycastTest.Instance.Parent ~= roomFolder and LeftRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if RightRaycastTest and RightRaycastTest.Instance.Parent ~= roomFolder and RightRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if DownRaycastTest and DownRaycastTest.Instance.Parent ~= roomFolder and DownRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if not everythingFine then
					myPart:SetAttribute("Bridgeable"..myDirection, true)

					for _, v in pairs(BridgeParts) do
						game:GetService("Debris"):AddItem(v, 0)
					end

					return GenerateRoomProcess(roomFolder, roomType)
				end

			end

		else

			myPart:SetAttribute("Bridgeable"..myDirection, true)

			for _, v in pairs(BridgeParts) do
				game:GetService("Debris"):AddItem(v, 0)
			end

			return GenerateRoomProcess(roomFolder, roomType)

		end

	end

end

for x = 1, RoomInfo["MainRoomSizeX"], 1 do

	for z = 1, RoomInfo["MainRoomSizeZ"], 1 do

		local Platform = DefaultPlatform:Clone()
		local PlatformID = x + ((z-1)*RoomInfo["MainRoomSizeX"])
		Platform.Parent = MainRoomFolder
		Platform.Name = "Platform"..PlatformID
		Platform.Color = Color3.fromRGB(0, 255, 0)
		Platform.Position = RoomInfo["InitialPosition"] + Vector3.new((x-1)*20,0,(z-1)*20)
		

	end

end

SetBridgeables(MainRoomFolder, RoomInfo["MainRoomSizeX"])

while #RoomsFolder:GetChildren() < RoomInfo["RoomNumber"] do

	local NewRoom = Instance.new("Folder", RoomsFolder)
	NewRoom.Name = "Room"..#RoomsFolder:GetChildren()

	if #RoomsFolder:GetChildren() == 1 then

		GenerateRoomProcess(NewRoom, "FirstRoom")

	else

		GenerateRoomProcess(NewRoom, "Room")

	end

end

You need to create the walls after finishing all the rooms creation.

When you fix by creating the wall after finishing all rooms creation, this will fix too as well (i guess lol)

In hallways, I think you should run the “SetBridgeables” by all them and them create walls as if they’re rooms

1 Like

Most walls are being generated but some aren’t… idk how to fix that

local RS = game:GetService("ReplicatedStorage")
local Platforms = RS:WaitForChild("Platforms")
local DefaultPlatform = Platforms:WaitForChild("Default")

local PlatformsFolder = Instance.new("Folder", workspace)
PlatformsFolder.Name = "Platforms"

local MainRoomFolder = Instance.new("Folder", PlatformsFolder)
MainRoomFolder.Name = "MainRoom"
local RoomsFolder = Instance.new("Folder", PlatformsFolder)
RoomsFolder.Name = "Rooms"
local HallsFolder = Instance.new("Folder", PlatformsFolder)
HallsFolder.Name = "Halls"
local WallsFolder = Instance.new("Folder", workspace)
WallsFolder.Name = "Walls"

-- In RoomInfo, you can adjust somethings on generation
local RoomInfo = {
	["RoomNumber"] = math.random(7, 10), -- How many rooms are there
	["MainRoomSizeX"] = math.random(3,6), -- The X number of platforms that MainRoom will have
	["MainRoomSizeZ"] = math.random(3,6), -- The Y number of platforms that MainRoom will have
	["InitialPosition"] = Vector3.new(0,0,0), -- The initial position of it (the first main room platform will spawn at this coordinates)
	["HallsMinSize"] = 3, -- The min size that a corridor must have
	["HallsMaxSize"] = 6, -- The max size that a corridor must have
}

local function SetBridgeables(parent, sizeX)
	


	for _, Platform: Part in pairs(parent:GetChildren()) do

		Platform:SetAttribute("BridgeableUp", true)
		Platform:SetAttribute("BridgeableRight", true)
		Platform:SetAttribute("BridgeableLeft", true)
		Platform:SetAttribute("BridgeableDown", true)

		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
		RayParams.FilterType = Enum.RaycastFilterType.Include

		local RaycastTest1 = workspace:Raycast(Platform.Position + Vector3.new(0, 100, 20), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest2 = workspace:Raycast(Platform.Position + Vector3.new(-20, 100, 0), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest3 = workspace:Raycast(Platform.Position + Vector3.new(20, 100, 0), Vector3.new(0,-10000,0), RayParams)
		local RaycastTest4 = workspace:Raycast(Platform.Position + Vector3.new(0, 100, -20), Vector3.new(0,-10000,0), RayParams)

		if RaycastTest1 then
			Platform:SetAttribute("BridgeableUp", false)
		end

		if RaycastTest2 then
			Platform:SetAttribute("BridgeableRight", false)
		end

		if RaycastTest3 then
			Platform:SetAttribute("BridgeableLeft", false)
		end

		if RaycastTest4 then
			Platform:SetAttribute("BridgeableDown", false)
		end
		
		
	end
end

local function DesignAHallPlan(size, initialPosition, direction, timesTrying)

	local hall = {}
	local nowPosition = initialPosition

	local myDirection = direction

	for i = 1,size,1 do

		local RayParams = RaycastParams.new()
		RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
		RayParams.FilterType = Enum.RaycastFilterType.Include

		local RaycastTest = workspace:Raycast(nowPosition + (myDirection * 20) + Vector3.new(0,100,0), Vector3.new(0,-10000,0), RayParams)

		if not RaycastTest then
			nowPosition = nowPosition + (myDirection * 20)
			table.insert(hall, nowPosition)

			if math.random(1,4) == 1 and i > 2 then
				if myDirection.X ~= 0 then
					if math.random(1,2) == 1 then
						myDirection = Vector3.new(0,0,1)
					else
						myDirection = Vector3.new(0,0,-1)
					end
				else
					if math.random(1,2) == 1 then
						myDirection = Vector3.new(1,0,0)
					else
						myDirection = Vector3.new(-1,0,0)
					end
				end
			end

		else
			if not timesTrying then
				return DesignAHallPlan(size, initialPosition, direction, 1)
			else
				if timesTrying > 20 then
					return nil
				else
					return DesignAHallPlan(size, initialPosition, direction, timesTrying + 1)
				end
			end
		end

	end

	return hall, myDirection

end

local function GenerateRoom(lastBridge, direction, parent, timesTrying)

	local myDirection = direction

	local SizeX = math.random(4,7)
	local SizeZ = math.random(4,7)

	local InitialPosition = lastBridge.Position + (myDirection * 20)

	local preventMultiplier = 1

	if direction == Vector3.new(-1,0,0) or direction == Vector3.new(0,0,-1) then
		preventMultiplier = -1
	end

	for x = 1, SizeX, 1 do

		for z = 1, SizeZ, 1 do

			local RayParams = RaycastParams.new()
			RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
			RayParams.FilterType = Enum.RaycastFilterType.Include

			local RaycastTest = workspace:Raycast(InitialPosition + Vector3.new((x-1)*20*preventMultiplier,0,(z-1)*20*preventMultiplier) + Vector3.new(0,100,0), Vector3.new(0,-10000,0), RayParams)

			if RaycastTest then

				for _, v in pairs(parent:GetChildren()) do

					game:GetService("Debris"):AddItem(v, 0)

				end

				if not timesTrying then
					return GenerateRoom(lastBridge, direction, parent, 1)
				else
					if timesTrying > 20 then
						return nil
					else
						return GenerateRoom(lastBridge, direction, parent, timesTrying+1)
					end
				end

			end

			local Platform = DefaultPlatform:Clone()
			local PlatformID = x + ((z-1)*SizeX)

			Platform.Parent = parent
			Platform.Name = "Platform"..PlatformID
			Platform.Color = Color3.fromRGB(49, 176, 255)
			Platform.Position = InitialPosition + Vector3.new((x-1)*20*preventMultiplier,0,(z-1)*20*preventMultiplier)

		end

	end

	return SizeX

end

local function GenerateRoomProcess(roomFolder, roomType)

	if roomType == "FirstRoom" then

		local BridgeSize = math.random(RoomInfo["HallsMinSize"],RoomInfo["HallsMaxSize"])
		local BridgeablesParts = {}

		for _, v in pairs(MainRoomFolder:GetChildren()) do

			local canInsert = false

			if v:GetAttribute("BridgeableUp") then
				canInsert = true
			elseif v:GetAttribute("BridgeableLeft") then
				canInsert = true
			elseif v:GetAttribute("BridgeableRight") then
				canInsert = true
			elseif v:GetAttribute("BridgeableDown") then
				canInsert = true
			end

			if canInsert then
				table.insert(BridgeablesParts, v)
			end

		end

		local myPart = BridgeablesParts[math.random(1,#BridgeablesParts)]
		local Directions = {}

		if myPart:GetAttribute("BridgeableUp") then
			table.insert(Directions, "Up")
		end
		if myPart:GetAttribute("BridgeableLeft") then
			table.insert(Directions, "Left")
		end
		if myPart:GetAttribute("BridgeableRight") then
			table.insert(Directions, "Right")
		end
		if myPart:GetAttribute("BridgeableDown") then
			table.insert(Directions, "Down")
		end

		local myDirection = Directions[math.random(1, #Directions)]

		myPart:SetAttribute("Bridgeable"..myDirection, false)

		local vectorDirection = Vector3.new(0,0,0)

		if myDirection == "Up" then
			vectorDirection = Vector3.new(0,0,1)
		elseif myDirection == "Left" then
			vectorDirection = Vector3.new(1,0,0)
		elseif myDirection == "Right" then
			vectorDirection = Vector3.new(-1,0,0)
		elseif myDirection == "Down" then
			vectorDirection = Vector3.new(0,0,-1)
		end

		local HallPlan = DesignAHallPlan(BridgeSize, myPart.Position, vectorDirection)
		local LastBridge = nil
		local BridgeParts = {}

		if not HallPlan then
			myPart:SetAttribute("Bridgeable"..myDirection, true)
			return GenerateRoomProcess(roomFolder, roomType)
		end

		for i, v in pairs(HallPlan) do

			local Platform = DefaultPlatform:Clone()
			Platform.Parent = HallsFolder
			Platform.Name = "Hall"..i
			Platform.Position = v
			Platform.Color = Color3.fromRGB(80,80,80)

			table.insert(BridgeParts, Platform)

			if i == #HallPlan then

				LastBridge = Platform

			end

		end
		
		--SetBridgeables(HallsFolder, 1)

		local RoomSizeX = GenerateRoom(LastBridge, vectorDirection, roomFolder)

		if RoomSizeX then

			SetBridgeables(roomFolder, RoomSizeX)

			for _, v in pairs(roomFolder:GetDescendants()) do

				local everythingFine = true

				local RayParams = RaycastParams.new()
				RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
				RayParams.FilterType = Enum.RaycastFilterType.Include

				local UpRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,20), Vector3.new(0,-10000,0), RayParams)
				local RightRaycastTest = workspace:Raycast(v.Position + Vector3.new(-20,100,0), Vector3.new(0,-10000,0), RayParams)
				local LeftRaycastTest = workspace:Raycast(v.Position + Vector3.new(20,100,0), Vector3.new(0,-10000,0), RayParams)
				local DownRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,-20), Vector3.new(0,-10000,0), RayParams)

				if UpRaycastTest and UpRaycastTest.Instance.Parent ~= roomFolder and UpRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if LeftRaycastTest and LeftRaycastTest.Instance.Parent ~= roomFolder and LeftRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if RightRaycastTest and RightRaycastTest.Instance.Parent ~= roomFolder and RightRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if DownRaycastTest and DownRaycastTest.Instance.Parent ~= roomFolder and DownRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if not everythingFine then
					myPart:SetAttribute("Bridgeable"..myDirection, true)

					for _, v in pairs(BridgeParts) do
						game:GetService("Debris"):AddItem(v, 0)
					end

					return GenerateRoomProcess(roomFolder, roomType)
				end

			end

		else
			myPart:SetAttribute("Bridgeable"..myDirection, true)

			for _, v in pairs(BridgeParts) do
				game:GetService("Debris"):AddItem(v, 0)
			end

			return GenerateRoomProcess(roomFolder, roomType)

		end

	else

		local BridgeSize = math.random(RoomInfo["HallsMinSize"],RoomInfo["HallsMaxSize"])
		local BridgeablesParts = {}

		for _, v in pairs(MainRoomFolder:GetDescendants()) do

			local canInsert = false

			if v:GetAttribute("BridgeableUp") then
				canInsert = true
			elseif v:GetAttribute("BridgeableLeft") then
				canInsert = true
			elseif v:GetAttribute("BridgeableRight") then
				canInsert = true
			elseif v:GetAttribute("BridgeableDown") then
				canInsert = true
			end

			if canInsert then
				table.insert(BridgeablesParts, v)
			end

		end

		if math.random(1,15) == 1 then
			for _, v in pairs(RoomsFolder:GetDescendants()) do

				local canInsert = false

				if v:GetAttribute("BridgeableUp") then
					canInsert = true
				elseif v:GetAttribute("BridgeableLeft") then
					canInsert = true
				elseif v:GetAttribute("BridgeableRight") then
					canInsert = true
				elseif v:GetAttribute("BridgeableDown") then
					canInsert = true
				end

				if canInsert then
					table.insert(BridgeablesParts, v)
				end

			end
		end

		local myPart = BridgeablesParts[math.random(1,#BridgeablesParts)]
		local Directions = {}

		if myPart:GetAttribute("BridgeableUp") then
			table.insert(Directions, "Up")
		end
		if myPart:GetAttribute("BridgeableLeft") then
			table.insert(Directions, "Left")
		end
		if myPart:GetAttribute("BridgeableRight") then
			table.insert(Directions, "Right")
		end
		if myPart:GetAttribute("BridgeableDown") then
			table.insert(Directions, "Down")
		end

		local myDirection = Directions[math.random(1, #Directions)]

		myPart:SetAttribute("Bridgeable"..myDirection, false)

		local vectorDirection = Vector3.new(0,0,0)

		if myDirection == "Up" then
			vectorDirection = Vector3.new(0,0,1)
		elseif myDirection == "Left" then
			vectorDirection = Vector3.new(1,0,0)
		elseif myDirection == "Right" then
			vectorDirection = Vector3.new(-1,0,0)
		elseif myDirection == "Down" then
			vectorDirection = Vector3.new(0,0,-1)
		end

		local HallPlan, finalDirection = DesignAHallPlan(BridgeSize, myPart.Position, vectorDirection)
		local LastBridge = nil
		local BridgeParts = {}

		if not HallPlan then
			myPart:SetAttribute("Bridgeable"..myDirection, true)
			return GenerateRoomProcess(roomFolder, roomType)
		end

		for i, v in pairs(HallPlan) do

			local Platform = DefaultPlatform:Clone()
			Platform.Parent = HallsFolder
			Platform.Name = "Hall"..i
			Platform.Position = v
			Platform.Color = Color3.fromRGB(80,80,80)
	
			
			

			table.insert(BridgeParts, Platform)
			
			

			if i == #HallPlan then

				LastBridge = Platform

			end

		end

		local RoomSizeX = GenerateRoom(LastBridge, finalDirection, roomFolder)

		if RoomSizeX then

			SetBridgeables(roomFolder, RoomSizeX)

			for _, v in pairs(roomFolder:GetDescendants()) do

				local everythingFine = true

				local RayParams = RaycastParams.new()
				RayParams.FilterDescendantsInstances = PlatformsFolder:GetChildren()
				RayParams.FilterType = Enum.RaycastFilterType.Include

				local UpRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,20), Vector3.new(0,-10000,0), RayParams)
				local RightRaycastTest = workspace:Raycast(v.Position + Vector3.new(-20,100,0), Vector3.new(0,-10000,0), RayParams)
				local LeftRaycastTest = workspace:Raycast(v.Position + Vector3.new(20,100,0), Vector3.new(0,-10000,0), RayParams)
				local DownRaycastTest = workspace:Raycast(v.Position + Vector3.new(0,100,-20), Vector3.new(0,-10000,0), RayParams)

				if UpRaycastTest and UpRaycastTest.Instance.Parent ~= roomFolder and UpRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if LeftRaycastTest and LeftRaycastTest.Instance.Parent ~= roomFolder and LeftRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if RightRaycastTest and RightRaycastTest.Instance.Parent ~= roomFolder and RightRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if DownRaycastTest and DownRaycastTest.Instance.Parent ~= roomFolder and DownRaycastTest.Instance.Parent ~= HallsFolder then
					everythingFine = false
				end

				if not everythingFine then
					myPart:SetAttribute("Bridgeable"..myDirection, true)

					for _, v in pairs(BridgeParts) do
						game:GetService("Debris"):AddItem(v, 0)
					end

					return GenerateRoomProcess(roomFolder, roomType)
				end

			end

		else

			myPart:SetAttribute("Bridgeable"..myDirection, true)

			for _, v in pairs(BridgeParts) do
				game:GetService("Debris"):AddItem(v, 0)
			end

			return GenerateRoomProcess(roomFolder, roomType)

		end

	end

end

for x = 1, RoomInfo["MainRoomSizeX"], 1 do

	for z = 1, RoomInfo["MainRoomSizeZ"], 1 do

		local Platform = DefaultPlatform:Clone()
		local PlatformID = x + ((z-1)*RoomInfo["MainRoomSizeX"])
		Platform.Parent = MainRoomFolder
		Platform.Name = "Platform"..PlatformID
		Platform.Color = Color3.fromRGB(0, 255, 0)
		Platform.Position = RoomInfo["InitialPosition"] + Vector3.new((x-1)*20,0,(z-1)*20)
		

	end

end


SetBridgeables(MainRoomFolder, RoomInfo["MainRoomSizeX"])

while #RoomsFolder:GetChildren() < RoomInfo["RoomNumber"] do
	

	warn("not enough rooms")
	local NewRoom = Instance.new("Folder", RoomsFolder)
	NewRoom.Name = "Room"..#RoomsFolder:GetChildren()

	if #RoomsFolder:GetChildren() == 1 then

		GenerateRoomProcess(NewRoom, "FirstRoom")

	else

		GenerateRoomProcess(NewRoom, "Room")

	end

end

SetBridgeables(HallsFolder, 20)


for _,Platform in pairs(workspace:GetDescendants()) do

	local Attributes = {
		BridgeableUp = Platform:GetAttribute("BridgeableUp"),
		BridgeableDown = Platform:GetAttribute("BridgeableDown"),
		BridgeableLeft = Platform:GetAttribute("BridgeableLeft"),
		BridgeableRight = Platform:GetAttribute("BridgeableRight"),
	}

	if Attributes.BridgeableUp then
		local Wall = Instance.new("Part", WallsFolder)
		Wall.Anchored = true
		Wall.Size = Vector3.new(20, 10, 1)
		Wall.Position = Platform.Position + Vector3.new(0,5,10)
		Wall.Color = Color3.new(0, 0.917647, 1)
		Platform.Destroying:Connect(function()
			Wall:Destroy()
		end)
	end
	if Attributes.BridgeableDown then
		local Wall = Instance.new("Part", WallsFolder)
		Wall.Anchored = true
		Wall.Size = Vector3.new(20, 10, 1)
		Wall.Position = Platform.Position + Vector3.new(0,5,-10)
		Wall.Color = Color3.new(0.0431373, 0.435294, 0)
		Platform.Destroying:Connect(function()
			Wall:Destroy()
		end)
	end
	if Attributes.BridgeableLeft then
		local Wall = Instance.new("Part", WallsFolder)
		Wall.Anchored = true
		Wall.Size = Vector3.new(1, 10, 20) 
		Wall.Rotation = Vector3.new(0,0,0) 
		Wall.Position = Platform.Position + Vector3.new(10,5,0)
		Wall.Color = Color3.new(1, 0, 0.0156863)
		Platform.Destroying:Connect(function()
			Wall:Destroy()
		end)
	end
	if Attributes.BridgeableRight then
		local Wall = Instance.new("Part", WallsFolder)
		Wall.Anchored = true
		Wall.Size = Vector3.new(1, 10, 20)
		Wall.Rotation = Vector3.new(0,0,0) 
		Wall.Position = Platform.Position + Vector3.new(-10,5,0)
		Wall.Color = Color3.new(0, 0.133333, 1)
		Platform.Destroying:Connect(function()
			Wall:Destroy()
		end)
	end
end

Do you know what the issue is that some hallway walls arent being generated?

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